Quando olho para o plano de execução real de algumas de minhas consultas, percebo que as constantes literais usadas em uma cláusula WHERE aparecem como uma cadeia aninhada de varredura escalar e constante calculada .
Para reproduzir isso, eu uso a seguinte tabela
CREATE TABLE Table1 (
[col1] [bigint] NOT NULL,
[col2] [varchar](50) NULL,
[col3] [char](200) NULL
)
CREATE NONCLUSTERED INDEX IX_Table1 ON Table1 (col1 ASC)
Com alguns dados nele:
INSERT INTO Table1(col1) VALUES (1),(2),(3),
(-9223372036854775808),
(9223372036854775807),
(2147483647),(-2147483648)
Quando executo a seguinte consulta (sem sentido):
SELECT a.col1, a.col2
FROM Table1 a, Table1 b
WHERE b.col1 > 2147483648
Vejo que ele fará um desenho de Loop Aninhado no resultado de Index Seek e um cálculo escalar (a partir de uma constante).
Observe que o literal é maior que maxint. Ajuda a escrever CAST(2147483648 as BIGINT)
. Alguma idéia de por que o MSSQL está adiando isso para o plano de execução e existe uma maneira mais curta de evitá-lo do que usar o elenco? Isso afeta os parâmetros vinculados às instruções preparadas (do jtds JDBC) também?
O cálculo escalar nem sempre é feito (parece ser específico de busca de índice ). E às vezes o analisador de consultas não mostra isso graficamente, mas como col1 < scalar(expr1000)
nas propriedades do predicado.
Eu vi isso com o MS SSMS 2016 (13.0.16100.1) e SQL Server 2014 Expres Edition 64 bits no Windows 7, mas acho que é um comportamento geral.
Mostra que o literal
2147483648
é interpretado comonumeric(10,0)
. Esse comportamento é anterior à introdução dobigint
no SQL Server (2000).Não há sintaxe para indicar que um literal deve ser tratado como
bigint
- adicionar um explícitoCAST
é a melhor solução. O artigo Buscas Dinâmicas e Conversões Implícitas Ocultas discute o resto do aparato no plano.O próprio plano mostra que os loops aninhados têm um predicado de busca em
Você pode usar uma sessão de eventos estendidos
query_trace_column_values
para ver que são os seguintes.O XML no plano também mostra isso
Isso não significa que ele está literalmente fazendo uma comparação
< null
em vez dePortanto, o efeito líquido é que seu predicado de consulta
b.col1 > CAST(2147483648 AS NUMERIC(10, 0))
ainda acaba com uma busca contrab.col1 > CAST(2147483648 AS BIGINT)
Eu não usei jtds JDBC, mas presumo que permita definir tipos de dados de parâmetro? Nesse caso, apenas certifique-se de que os parâmetros sejam o tipo de dados correto que corresponda à coluna (
bigint
) para que não haja necessidade de o SQL Server lidar com tipos de dados incompatíveis.Em relação à minha pergunta sobre as declarações preparadas pelo JDBC. jTDS usa
sp_prepare
/sp_execute
(no modo padrãoprepareSQL=3
).Com a seguinte consulta ( source ):
Eu posso ver a instrução preparada conforme emitida pelo JTDS e ela declara a variável conforme
(@P0 bigint)...
o esperado.Portanto, tudo isso é bom e preciso lembrar que, ao experimentar os planos de execução, é melhor definir variáveis de tipo local em vez de substituí-las por literais (e/ou usar
sp_execute
para acessar o plano de execução em cache).