¿Qué hace que una declaración SQL sea sargable?

253

Por definición (al menos por lo que he visto) sargable significa que una consulta es capaz de hacer que el motor de consulta optimice el plan de ejecución que utiliza la consulta. He intentado buscar las respuestas, pero no parece haber mucho sobre el tema. Entonces la pregunta es, ¿qué hace o no que una consulta SQL sea sargable? Cualquier documentación sería muy apreciada.

Para referencia: SARGable

DForck42
fuente
58
+1 para "sargable". Esa es mi palabra del día para hoy. :-p
BFree
1
También podría agregar a la respuesta de Adam, que las montañas de información son en la mayoría de los casos extremadamente particulares para cada motor de DB.
Hoagie
31
SARG = ARGumento de búsqueda. Lo curioso es: "SARG" en alemán significa "Ataúd", así que siempre tengo que sonreír cuando la gente habla de SARGABLE: ¿se puede poner en un ataúd? :-)
marc_s
La sargabilidad depende de su entorno. MySQL está documentado aquí: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer
Tener campos de texto libre en lugar de "tablas de búsqueda" también va en contra del espíritu de hacer una consulta sargable. Los usuarios escriben mal las cosas al ingresar texto libre (por ejemplo, el nombre de la ciudad), mientras que las tablas de búsqueda obligan a los usuarios a elegir una entrada escrita correctamente. Vale la pena el pequeño problema adicional, porque esto puede indexarse ​​correctamente en lugar de usar LIKE '% ...%' en el predicado.
Ingeniero invertido

Respuestas:

256

Lo más común que hará que una consulta no sea sargable es incluir un campo dentro de una función en la cláusula where:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

El optimizador de SQL no puede usar un índice en myDate, incluso si existe uno. Literalmente tendrá que evaluar esta función para cada fila de la tabla. Mucho mejor de usar:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

Algunos otros ejemplos:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 
BradC
fuente
77
¿ GROUP BYIncluir una función dentro de hará que una consulta se vuelva no sargable?
Mike Bailey
1
Algunos motores de bases de datos (Oracle, PostgreSQL) admiten índices en expresiones, ¿no lo sabe?
Craig
3
¿Sería una versión aún mejor de WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))be SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Un chico de optimización me dijo una vez que usar OR en la cláusula where puede desviar consultas ...
High Plains Grifter
2
@HighPlainsGrifter, debe usar UNION ALL en esa consulta: la unión tiene un distintivo implícito, lo que hace que una consulta sea mucho más costosa de lo que debe ser cuando debe tener conjuntos de datos mutuamente excluyentes
Devin Lamothe
1
@BradC En MSSQL 2016, no hay diferencia en el plan de ejecución entre Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'y Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Ambos usan el índice en FullName y realizan una búsqueda de índice.
CEGRD
79

No hagas esto:

WHERE Field LIKE '%blah%'

Eso provoca una exploración de tabla / índice, porque el valor LIKE comienza con un carácter comodín.

No hagas esto:

WHERE FUNCTION(Field) = 'BLAH'

Eso causa una exploración de tabla / índice.

El servidor de la base de datos tendrá que evaluar FUNCTION () contra cada fila de la tabla y luego compararlo con 'BLAH'.

Si es posible, hazlo a la inversa:

WHERE Field = INVERSE_FUNCTION('BLAH')

Esto ejecutará INVERSE_FUNCTION () contra el parámetro una vez y aún permitirá el uso del índice.

playa
fuente
55
Su sugerencia al voltear la función realmente solo funcionaría cuando la función realiza un viaje de ida y vuelta a los datos (lo que significa que f (f (n)) = n).
Adam Robinson
55
Cierto. Pensé en agregar INVERSE_FUNCTION pero no quería ser confuso. Lo cambiaré
playa
9

En esta respuesta, supongo que la base de datos tiene suficientes índices de cobertura. Hay suficientes preguntas sobre este tema .

Muchas veces la sargabilidad de una consulta está determinada por el punto de inflexión de los índices relacionados. El punto de inflexión define la diferencia entre buscar y escanear un índice al unir una tabla o conjunto de resultados en otra. Una búsqueda es, por supuesto, mucho más rápida que escanear una tabla completa, pero cuando tiene que buscar muchas filas, una exploración podría tener más sentido.

Entonces, entre otras cosas, una instrucción SQL es más modificable cuando el optimizador espera que el número de filas resultantes de una tabla sea menor que el punto de inflexión de un posible índice en la tabla siguiente.

Puede encontrar una publicación detallada y un ejemplo aquí .

Dries Van Hansewijck
fuente
4

Para que una operación se considere sargable, no es suficiente que solo pueda usar un índice existente. En el ejemplo anterior, agregar una llamada de función contra una columna indexada en la cláusula where, probablemente tomaría ventaja del índice definido. "Escaneará", también conocido como recuperar todos los valores de esa columna (índice) y luego eliminar los que no coinciden con el valor del filtro proporcionado. Todavía no es lo suficientemente eficiente para tablas con un alto número de filas. Lo que realmente define la sargabilidad es la capacidad de consulta para atravesar el índice b-tree utilizando el método de búsqueda binaria que se basa en la eliminación de medio conjunto para la matriz de elementos ordenados. En SQL, se mostraría en el plan de ejecución como una "búsqueda de índice".

usuario2011845
fuente