Eu tenho a seguinte tabela e dados nela. Eu tenho dois índices nele: um que contém apenas algumas colunas da cláusula where e o outro contém todas as colunas da cláusula where.
Estou confuso em relação ao comportamento observado ao utilizar diferentes índices em minha consulta. Especificamente, quando emprego o primeiro índice, que contém apenas algumas colunas da cláusula where, noto um baixo número de leituras lógicas, mas um alto número de linhas lidas. Por outro lado, quando uso o índice contendo todas as colunas da cláusula where, o número de leituras lógicas aumenta enquanto o número de linhas lidas diminui. No primeiro cenário, existem predicados residuais, fazendo com que o mecanismo verifique todas as linhas recuperadas da operação de busca. Porém, no segundo cenário, o motor busca diretamente os valores necessários. Diante disso, eu anteciparia um número menor de leituras lógicas no segundo caso. Eu apreciaria qualquer insight sobre por que isso está acontecendo. Obrigado!
CREATE TABLE myTable (
ID INT IDENTITY(1,1) PRIMARY KEY,
Column1 VARCHAR(50),
Column2 VARCHAR(50),
Column3 VARCHAR(50),
Column4 VARCHAR(50),
Column5 VARCHAR(50),
Column6 VARCHAR(50),
Column7 VARCHAR(50),
Column8 VARCHAR(50),
Column9 VARCHAR(50),
Column10 VARCHAR(50)
)
DECLARE @i INT = 1
DECLARE @j INT = 1
DECLARE @distinct_value_count INT = 20
DECLARE @distinct_value_count_with_more_rows INT = 3
DECLARE @rows_per_distinct_value INT = (20000 - (@distinct_value_count_with_more_rows * 2000)) / (@distinct_value_count - @distinct_value_count_with_more_rows)
WHILE @i <= @distinct_value_count
BEGIN
DECLARE @current_rows_per_value INT = @rows_per_distinct_value
IF @i <= @distinct_value_count_with_more_rows
BEGIN
SET @current_rows_per_value = @rows_per_distinct_value + 2000
END
SET @j = 1
WHILE @j <= @current_rows_per_value
BEGIN
INSERT INTO myTable (Column1, Column2, Column3, Column4, Column5, Column6, Column7, Column8, Column9, Column10)
VALUES ('Value' + CAST(@i AS VARCHAR(2)),
'Value' + CAST(@j AS VARCHAR(5)),
'Value' + CAST(@j + 1 AS VARCHAR(5)),
'Value' + CAST(@j + 2 AS VARCHAR(5)),
'Value' + CAST(@j + 3 AS VARCHAR(5)),
'Value' + CAST(@j + 4 AS VARCHAR(5)),
'Value' + CAST(@j + 5 AS VARCHAR(5)),
'Value' + CAST(@j + 6 AS VARCHAR(5)),
'Value' + CAST(@j + 7 AS VARCHAR(5)),
'Value' + CAST(@j + 8 AS VARCHAR(5)))
SET @j = @j + 1
END
SET @i = @i + 1
END
Alter Table dbo.myTable
Add Column11 varchar(50), Column12 varchar(50)
Alter Table dbo.myTable
Add dateModified datetime
Update dbo.myTable
set Column11 = Column1
,Column12 = Column1
Update Top (10) dbo.myTable
Set Column11 = 'Value7'
Where Column1 = 'Value1'
Update Top (10) dbo.myTable
Set Column12 = 'Value7'
Where Column1 = 'Value1'
Update Top (10) dbo.myTable
Set Column11 = 'Value6'
Where Column1 = 'Value1'
Update Top (10) dbo.myTable
Set Column12 = 'Value6'
Where Column1 = 'Value1'
Update Top (10) dbo.myTable
Set Column11 = 'Value5'
Where Column1 = 'Value1'
Update Top (10) dbo.myTable
Set Column12 = 'Value5'
Where Column1 = 'Value1'
Update dbo.myTable
set dateModified = getdate() + ID
CASO 1: LEITURA LÓGICA BAIXA, MAS O NÚMERO DE LINHAS É ALTO
Create NonClustered Index Idx_col1
On myTable(Column1, Column11)
Include (Column5, Column6,Column12, dateModified)
set Statistics io on
SELECT Column1
, Column11
, Column5
, Column6
, Column12
FROM myTable
WHERE Column1= 'Value1'
AND Column11 In( 'Value1','Value5','Value6', 'Value7')
And Column12 In ('Value1','Value6')
And dateModified > dateAdd(day,-5, getdate())
Plano de execução: https://www.brentozar.com/pastetheplan/?id=Sywz516Hh
Estatísticas de IO:
(2803 rows affected)
Table 'myTable'. Scan count 4, logical reads 34, physical reads 1, page server reads 0, read-ahead reads 23, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
(1 row affected)
CASO 2: LEITURA LÓGICA ALTA, MAS O NÚMERO DE LINHAS LIDAS É BAIXO
Create NonClustered Index Idx_col2 on myTable(Column1, Column11,Column12, dateModified)
Include (Column5, Column6)
set Statistics io on
SELECT Column1
, Column11
, Column5
, Column6
, Column12
FROM myTable
WHERE Column1= 'Value1'
AND Column11 In( 'Value1','Value5','Value6', 'Value7')
And Column12 In ('Value1','Value6')
And dateModified > dateAdd(day,-5, getdate())
Plano de Execução: https://www.brentozar.com/pastetheplan/?id=HyWbi1aSh
Estatísticas de IO:
(2803 rows affected)
Table 'myTable'. Scan count 8, logical reads 47, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
Você pode ver o motivo se reescrever as consultas com
UNION ALL
e, em seguida, obter o plano de execução real e observar as propriedades das buscas de índice.Para mim
Idx_col2
tem uma ramificação que retorna 2813 linhas e com 26 leituras lógicas e outras 7 buscas que retornam 0 linhas cada uma com 4 leituras lógicas - 26 + 7*4 = 54 (que é exatamente o mesmo que recebo com aor
consulta insinuandoIdx_col2
). Você precisará ver onde as coisas diferem para terminar com 47.O
Idx_col1
plano tem menos buscas (quatro) e o índice que ele busca tem um nível a menos para mim. Portanto, isso soma25 + 3*3 = 34
.A distinção entre 8 buscas e 4 buscas pode ser vista examinando os predicados de busca no plano de execução...
... e também aparece como o
Scan count
em seusSTATISTICS IO
resultados.(Consulte também " Quando uma busca não é uma busca? ")
(
UNION ALL
reescrever )