TL; DR
Como esta pregunta sigue obteniendo puntos de vista, la resumiré aquí para que los recién llegados no tengan que sufrir la historia:
JOIN table t ON t.member = @value1 OR t.member = @value2 -- this is slow as hell
JOIN table t ON t.member = COALESCE(@value1, @value2) -- this is blazing fast
-- Note that here if @value1 has a value, @value2 is NULL, and vice versa
Me doy cuenta de que esto podría no ser un problema de todos, pero al resaltar la sensibilidad de las cláusulas ON, podría ayudarlo a mirar en la dirección correcta. En cualquier caso, el texto original está aquí para futuros antropólogos:
Texto original
Considere la siguiente consulta simple (solo 3 tablas involucradas)
SELECT
l.sku_id AS ProductId,
l.is_primary AS IsPrimary,
v1.category_name AS Category1,
v2.category_name AS Category2,
v3.category_name AS Category3,
v4.category_name AS Category4,
v5.category_name AS Category5
FROM category c4
JOIN category_voc v4 ON v4.category_id = c4.category_id and v4.language_code = 'en'
JOIN category c3 ON c3.category_id = c4.parent_category_id
JOIN category_voc v3 ON v3.category_id = c3.category_id and v3.language_code = 'en'
JOIN category c2 ON c2.category_id = c3.category_id
JOIN category_voc v2 ON v2.category_id = c2.category_id and v2.language_code = 'en'
JOIN category c1 ON c1.category_id = c2.parent_category_id
JOIN category_voc v1 ON v1.category_id = c1.category_id and v1.language_code = 'en'
LEFT OUTER JOIN category c5 ON c5.parent_category_id = c4.category_id
LEFT OUTER JOIN category_voc v5 ON v5.category_id = c5.category_id and v5.language_code = @lang
JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
l.category_id = c4.category_id OR
l.category_id = c5.category_id
)
WHERE c4.[level] = 4 AND c4.version_id = 5
Esta es una consulta bastante simple, la única parte confusa es la última unión de categoría, es así porque el nivel de categoría 5 puede o no existir. Al final de la consulta, estoy buscando información de categoría por ID de producto (ID de SKU), y ahí es donde entra la tabla muy grande category_link. Finalmente, la tabla #Ids es solo una tabla temporal que contiene 10'000 Ids.
Cuando se ejecuta, obtengo el siguiente plan de ejecución real:
Como puede ver, casi el 90% del tiempo se gasta en los bucles anidados (unión interna). Aquí hay información adicional sobre esos bucles anidados:
Tenga en cuenta que los nombres de la tabla no coinciden exactamente porque edité los nombres de la tabla de consulta para facilitar su lectura, pero es bastante fácil de combinar (ads_alt_category = category). ¿Hay alguna forma de optimizar esta consulta? También tenga en cuenta que en producción, la tabla temporal #Ids no existe, es un parámetro de valor de tabla de los mismos 10'000 Ids pasados al procedimiento almacenado.
Información adicional:
- índices de categoría en category_id y parent_category_id
- category_voc index en category_id, language_code
- category_link index en sku_id, category_id
Editar (resuelto)
Como se señaló en la respuesta aceptada, el problema era la cláusula OR en la categoría JOIN. Sin embargo, el código sugerido en la respuesta aceptada es muy lento, incluso más lento que el código original. Una solución mucho más rápida y también más limpia es simplemente reemplazar la condición JOIN actual con lo siguiente:
JOIN category_link l on l.sku_id IN (SELECT value FROM @p1) AND l.category_id = COALESCE(c5.category_id, c4.category_id)
Este ajuste minucioso es la solución más rápida, probado contra la doble unión de la respuesta aceptada y también probado contra la APLICACIÓN CRUZADA según lo sugerido por valverij.