Por que não há verificação completa (no SQL 2008 R2 e 2012)?
Dados de teste:
DROP TABLE dbo.TestTable
GO
CREATE TABLE dbo.TestTable
(
TestTableID INT IDENTITY PRIMARY KEY,
VeryRandomText VarChar(50),
VeryRandomText2 VarChar(50)
)
Go
Set NoCount ON
Declare @i int
Set @i = 0
While @i < 10000
Begin
Insert Into dbo.TestTable(VeryRandomText, VeryRandomText2)
Values(Cast(Rand()*10000000 as VarChar(50)), Cast(Rand()*10000000 as VarChar(50)));
Set @i = @i + 1;
End
Go
CREATE Index IX_VeryRandomText On dbo.TestTable
(
VeryRandomText
)
Go
Ao executar a consulta:
Select * From dbo.TestTable Where VeryRandomText = N'111' -- bad
Receba um aviso (como esperado, porque comparando os dados nchar com a coluna varchar):
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(nvarchar(50),[DemoDatabase].[dbo].[TestTable].[VeryRandomText],0)" />
Mas então vejo o plano de execução e posso ver que ele não está usando a varredura completa como eu esperaria, mas sim a busca de índice.
Claro, isso é bom, porque neste caso particular a execução é muito mais rápida do que se houvesse varredura completa.
Mas não consigo entender como o SQL Server tomou a decisão de fazer esse plano.
Além disso, se o agrupamento do servidor fosse agrupamentos do Windows no nível do servidor e no nível do banco de dados de agrupamento do SQL Server, isso causaria uma verificação completa na mesma consulta.
Ao comparar valores de diferentes tipos de dados, o SQL Server segue as regras de precedência de tipo de dados . Como nvarchar tem precedência mais alta que varchar, o SQL Server precisa converter os dados da coluna em nvarchar antes de comparar valores. Isso significa aplicar uma função na coluna e isso tornaria a consulta não sargável.
O SQL Server, no entanto, faz o melhor para protegê-lo de seus erros, então ele usa uma técnica descrita por Paul White na postagem do blog Buscas dinâmicas e conversões implícitas ocultas para fazer uma busca por um intervalo de valores e, em seguida, fazer a comparação final, com o conversão do valor da coluna para nvarchar, em um predicado residual para filtrar quaisquer falsos positivos.
Como você observou, isso não funciona quando o agrupamento da coluna é um agrupamento SQL. A razão para isso, acredito, pode ser encontrada no artigo Comparando agrupamentos SQL com agrupamentos do Windows
Basicamente, um agrupamento do Windows usa o mesmo algoritmo para varchar e nvarchar, onde um agrupamento SQL usa um algoritmo diferente para dados varchar e o mesmo algoritmo que um agrupamento do Windows para dados nvarchar.
Portanto, ir de varchar para nvarchar em um agrupamento do Windows usará o mesmo algoritmo e o SQL Server pode produzir um intervalo de valores, no seu caso, um nvarchar literal para obter linhas do índice de coluna de agrupamento SQL varchar. No entanto, quando o agrupamento da coluna varchar é um SQL Collation que não é possível devido ao algoritmo diferente usado.
Atualizar:
Uma demonstração das diferentes ordens de classificação para colunas varchar usando windows e sql collation.
SQL Fiddle
Configuração do esquema do MS SQL Server 2014 :
Consulta 1 :
Resultados :
Consulta 2 :
Resultados :
Você deve se lembrar que os nós folha de um índice não agrupado consistem em páginas de índice que contêm a chave de agrupamento ou RID para localizar a linha de dados.
Em sua cláusula where, você declara
VeryRandomText = N'111'
Como existe um índice não clusterizado em VeryRandomText (criar índice criará índice não clusterizado, a menos que você diga explicitamente para criar um clusterizado), a maneira mais barata de encontrar os dados é digitalizar o índice para encontrar o rowid e em seguida, busque os dados para a linha.Se você criar um índice clusterizado
ou uma chave primária em VeryRandomText, você obteria uma varredura desse índice.
Veja livros online ou aqui: http://www.sqlforge.com/w/Clustered_index,_nonclustered_index,_or_heap