¿Por qué esta búsqueda en BIGINT col tiene operadores de bucle anidado, escalar, calcular escalar y constante adicional?


8

Cuando miro el plan de ejecución real de algunas de mis consultas, noto que las constantes literales utilizadas en una cláusula WHERE se muestran como una cadena anidada de escaneo constante y escalar de cálculo .

captura de pantalla de sql studio

Para reproducir esto, uso la siguiente tabla

CREATE TABLE Table1 (
    [col1] [bigint] NOT NULL,
    [col2] [varchar](50) NULL,
    [col3] [char](200) NULL
)
CREATE NONCLUSTERED INDEX IX_Table1 ON Table1 (col1 ASC)

Con algunos datos en él:

INSERT INTO Table1(col1) VALUES (1),(2),(3),
                               (-9223372036854775808),
                               (9223372036854775807),
                               (2147483647),(-2147483648)

Cuando ejecuto la siguiente consulta (sin sentido):

SELECT a.col1, a.col2
  FROM Table1 a, Table1 b
  WHERE b.col1 > 2147483648

Veo que hará un dibujo de Nested Loop en el resultado de Index Seek y un cálculo escalar (de una constante).

Tenga en cuenta que el literal es mayor que maxint. Ayuda a escribir CAST(2147483648 as BIGINT). ¿Alguna idea de por qué MSSQL está retrasando eso al plan de ejecución y hay una forma más corta de evitarlo que usar el yeso? ¿Afecta también los parámetros vinculados a las declaraciones preparadas (de jtds JDBC)?

El cálculo escalar no siempre se realiza (parece ser un índice de búsqueda específico). Y a veces el analizador de consultas no lo muestra gráficamente, sino como col1 < scalar(expr1000)en las propiedades del predicado.

He visto esto con MS SSMS 2016 (13.0.16100.1) y SQL Server 2014 Expres Edition 64bit en Windows 7, pero supongo que es un comportamiento general.

Respuestas:


8
SELECT thing, 
       sql_variant_property(thing,'basetype') AS basetype,
       sql_variant_property(thing,'precision') AS precision, 
       sql_variant_property(thing,'scale') AS scale
FROM (VALUES (2147483648)) V(thing)

Le muestra que el literal 2147483648se interpreta como numeric(10,0). Este comportamiento es anterior a la introducción de bigintSQL Server (2000).

No hay sintaxis para indicar que un literal debe tratarse como bigint: agregar un explícito CASTes la mejor solución. El artículo Búsqueda dinámica y conversiones implícitas ocultas analiza el resto del aparato en el plan.

El plan en sí muestra que los bucles anidados tienen un predicado de búsqueda en

Seek Keys[1]: Start: [tempdb].[dbo].[Table1].col1 > Scalar Operator([Expr1005]), 
                End: [tempdb].[dbo].[Table1].col1 < Scalar Operator([Expr1006])

Puede usar una sesión de eventos extendidos query_trace_column_valuespara ver que estos son los siguientes.

ingrese la descripción de la imagen aquí

El XML en el plan también muestra esto

  <DefinedValue>
    <ValueVector>
      <ColumnReference Column="Expr1005" />
      <ColumnReference Column="Expr1006" />
      <ColumnReference Column="Expr1004" />
    </ValueVector>
    <ScalarOperator ScalarString="GetRangeWithMismatchedTypes((2147483648.),NULL,(6))">
      <Intrinsic FunctionName="GetRangeWithMismatchedTypes">
        <ScalarOperator>
          <Const ConstValue="(2147483648.)" />
        </ScalarOperator>
        <ScalarOperator>
          <Const ConstValue="NULL" />
        </ScalarOperator>
        <ScalarOperator>
          <Const ConstValue="(6)" />
        </ScalarOperator>
      </Intrinsic>
    </ScalarOperator>
  </DefinedValue>

Esto no significa que literalmente esté haciendo una comparación < nullmás bien

Las expresiones de límite de rango usan NULL para representar 'ilimitado' en cualquier extremo. ( Fuente )

Entonces, el efecto neto es que su predicado de consulta b.col1 > CAST(2147483648 AS NUMERIC(10, 0))todavía termina con una búsqueda contrab.col1 > CAST(2147483648 AS BIGINT)

¿Afecta también los parámetros vinculados a las declaraciones preparadas (de jtds JDBC)?

No he usado jtds JDBC pero supongo que le permite definir tipos de datos de parámetros. Si es así, asegúrese de que los parámetros sean del tipo de datos correcto que coincida con la columna ( bigint) para que SQL Server no tenga que tratar con tipos de datos que no coinciden.


3

En relación con mi pregunta sobre las declaraciones preparadas de JDBC. jTDS usa sp_prepare/ sp_execute(en prepareSQL=3modo predeterminado ).

Con la siguiente consulta ( fuente ):

use database
select
    cp.objtype, st.text
from sys.dm_exec_cached_plans cp
cross apply sys.dm_exec_sql_text(cp.plan_handle) st
where cp.objtype = 'prepared' and st.text like '%TABLE%'

Puedo ver la declaración preparada emitida por JTDS, y declara la variable (@P0 bigint)...como se esperaba.

Entonces, todo esto es bueno y necesito recordar que al probar los planes de ejecución es mejor definir realmente las variables tipadas locales en lugar de reemplazarlas con literales (y / o usar sp_executepara aprovechar el plan de ejecución en caché).


1
Alternativamente, puede establecer una regla con usted para emitir sus literales al tipo de la columna con la que está haciendo coincidir.
Andriy M
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.