Com base nessas perguntas e nas respostas dadas:
SQL 2008 Server - perda de desempenho possivelmente relacionada a uma tabela muito grande
Eu tenho uma tabela em um banco de dados SupervisionP definida assim:
CREATE TABLE [dbo].[PenData](
[IDUkazatel] [smallint] NOT NULL,
[Cas] [datetime2](0) NOT NULL,
[Hodnota] [real] NULL,
[HodnotaMax] [real] NULL,
[HodnotaMin] [real] NULL,
CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED
(
[IDUkazatel] ASC,
[Cas] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[PenData] WITH NOCHECK ADD CONSTRAINT [FK_Data_Ukazatel] FOREIGN KEY([IDUkazatel])
REFERENCES [dbo].[Ukazatel] ([IDUkazatel])
ALTER TABLE [dbo].[PenData] CHECK CONSTRAINT [FK_Data_Ukazatel]
Ele contém cerca de 211 milhões de linhas.
Eu corro a seguinte declaração:
DECLARE @t1 DATETIME;
DECLARE @t2 DATETIME;
SET @t1 = GETDATE();
SELECT min(cas) from PenData p WHERE IDUkazatel=24
SELECT min(cas) from PenData p WHERE IDUkazatel=25
SET @t2 = GETDATE();
SELECT DATEDIFF(millisecond,@t1,@t2) AS elapsed_ms;
SET @t1 = GETDATE();
SELECT min(cas) from PenData p WHERE IDUkazatel=24 OR IDUkazatel=25
SET @t2 = GETDATE();
SELECT DATEDIFF(millisecond,@t1,@t2) AS elapsed_ms;
O resultado é mostrado aqui:
O terceiro SELECT também carrega muito mais dados no cache de memória do SQL Server.
Por que o terceiro SELECT é muito mais lento (8,5 s) do que os dois primeiros SELECTs (16 ms)? Como posso melhorar o desempenho do terceiro select com OR? Eu quero executar o seguinte comando SQL, mas parece-me que criar cursor e executar consultas separadas é muito mais rápido do que uma única seleção neste caso.
SELECT MIN(cas) from PenData p WHERE IDUkazatel IN (SELECT IDUkazatel FROM ...)
EDITAR
Como David sugeriu, passei o mouse sobre a seta gorda:
Para as duas primeiras consultas, tudo o que ele precisa fazer é verificar no índice clusterizado a primeira entrada para esse valor de
IDUkazatel
- devido à ordem do índice, essa linha será o valor mais baixo para cas para esse valor deIDUkazatel
.Na segunda consulta, essa otimização não é valor e provavelmente está procurando a primeira linha para , em
IDUkazatel=24
seguida, digitalizar o índice até a última linhaIDUkazatel=25
para encontrar o valor mínimo decas
todas essas linhas.Se você passar o mouse sobre a seta gorda, verá que ela está lendo muitas linhas (certamente todas as de 24, provavelmente todas as de 25 também), enquanto as setas finas na saída do plano para as outras duas mostram a
top
ação que faz com que apenas considere uma linha.Você pode tentar executar cada consulta e obter o mínimo para os mínimos encontrados:
Dito isso, parece que você tem uma tabela com valores em vez de uma cláusula
IDUkazatel
explícita .OR
O código abaixo funcionará com essa disposição, basta substituir o nome da tabela@T
pelo nome da tabela que contém osIDUkazatel
valores:Em um mundo ideal, o otimizador de consulta do SQL Server executaria essa reescrita para você, mas nem sempre considera essa opção hoje.