Tengo un extraño problema de compilación de consultas que es difícil de reproducir. Solo ocurre bajo una carga alta y no se puede repetir fácilmente.
- Hay una tabla T con las columnas A, B, C, D.
- Hay un índice agrupado no único en T (A, B, C, D).
- Hay una consulta SELECT * FROM T WHERE A = @ P1 AND B = @ P2 AND (C = @ P3 OR C = @ P4) AND D = @ P5. La condición de búsqueda está en todas las columnas del índice agrupado, la columna 3 tiene un OR.
¡El problema es que el plan de consulta para esta consulta tiene Buscar predicado solo en A y B! El predicado en C y D es un predicado ordinario, por lo que esto significa que el árbol de búsqueda en las columnas C y D no se utiliza.
Los tipos de datos para todos los parámetros coinciden con los tipos de datos de columna.
¿Alguien podría dar alguna pista sobre por qué esto podría estar sucediendo? La versión SQL es 2008 R2 (SP1) - 10.50.2789.0 (X64)
OPTION (RECOMPILE)
?Respuestas:
Para una consulta parametrizada No puede hacer dos búsquedas en
y
Porque si
@P3 = @P4
eso traería incorrectamente filas duplicadas. Por lo tanto, primero necesitaría un operador que eliminara los duplicados.A partir de una prueba rápida, este final parece depender del tamaño de la tabla, ya sea que lo obtenga o no. En la prueba a continuación
245
/246
filas se encuentra el punto de corte entre los planos (este también fue el punto de corte entre el ajuste del índice en una página y se convirtió en 2 páginas de hoja y una página raíz).1 páginas / 245 filas
Este plan tiene una búsqueda
A=1 AND B=2
con un predicado residual en(C=@C1 OR C=@C2) AND D=5
2 páginas de hoja / 246 filas
En el segundo plan, los operadores adicionales son responsables de eliminar los duplicados del
@C1,@C2
primero antes de realizar las búsquedas.La búsqueda en el segundo plan es en realidad una búsqueda de rango entre
A=1 AND B=2 AND C > Expr1010
yA=1 AND B=2 AND C < Expr1011
con un predicado residual activadoD=5
. Todavía no es una búsqueda de igualdad en las 4 columnas. Puede encontrar más información sobre los operadores de planes adicionales aquí .Agregar
OPTION (RECOMPILE)
le permite inspeccionar los valores de los parámetros para duplicados en tiempo de compilación y produce un plan con dos búsquedas de igualdad.También podrías lograr eso con
Pero en realidad, en este caso de prueba, probablemente sería contraproducente, ya que tener dos búsquedas en el índice de una sola página en lugar de una aumenta el IO lógico.
fuente
select .. union select ...
también le daría dos búsquedas más el paso adicional de eliminar duplicados del resultado.SELECT * FROM T WHERE A=1 AND B=2 AND C=@C1 AND D=5 UNION SELECT * FROM T WHERE A=1 AND B=2 AND C=@C2 AND D=5
podría eliminar incorrectamente los duplicados que deberían devolverse. En mi ejemplo, los datos donde perezosamente poblaba todos con el mismo valor que devolvería 1 fila no256
Totalmente de acuerdo con el análisis de Martin. Esta consulta no puede producir una búsqueda en las 4 columnas debido al predicado OR, a menos que (tal vez) con OPTION (RECOMPILE). Supongo que se trata de una consulta de aguja en un pajar, probablemente no desee la sobrecarga adicional.
Qué tal esto:
No probé esto, pero la parte else debería dar 2 búsquedas en los 4 valores y una unión barata a través de la concatenación. En caso de que ambas búsquedas terminen en la misma página, no creo que una lectura de página lógica adicional agregue mucho tiempo. Sin embargo, dependiendo de sus datos, las dos búsquedas pueden estar en páginas diferentes.
fuente