Puede obtener algo similar a la CARDINALITY
sugerencia de Oracle mediante el uso estratégico TOP
y una función definida por el usuario llamada MANY()
desarrollada por Adam Machanic . Analicemos algunos ejemplos. Estoy usando la base de datos AdventureWorks disponible gratuitamente. Supongamos que realmente necesito controlar el número de filas devueltas por la th
tabla derivada en la siguiente consulta:
SELECT
p.Name
, th.ProductId
, th.Quantity
, th.ActualCost
FROM Production.Product p
INNER JOIN (
SELECT ProductId, Quantity, ActualCost
FROM Production.TransactionHistory
) th ON p.ProductID = th.ProductID;
Como es, obtengo una estimación de 113443 filas:
Si necesito reducir la estimación th
, puedo usarla TOP
junto con la OPTIMIZE FOR
sugerencia de consulta para establecer un objetivo de fila. Aquí hay una forma de hacerlo:
DECLARE @row_goal BIGINT = 9223372036854775807;
SELECT
p.Name
, th.ProductId
, th.Quantity
, th.ActualCost
FROM Production.Product p
INNER JOIN (
SELECT TOP (@row_goal) ProductId, Quantity, ActualCost
FROM Production.TransactionHistory
) th ON p.ProductID = th.ProductID
OPTION (OPTIMIZE FOR (@row_goal = 1));
Podemos ver que la estimación es solo 1 fila:
Configuré @row_goal
el mayor BIGINT
valor posible para evitar cambiar los resultados. La OPTIMIZE FOR
sugerencia de la consulta indica al optimizador que optimice la consulta como si fuera @row_goal
igual a 1. Obtendré los mismos resultados pero la consulta se optimizará de manera diferente.
Aumentar una estimación de cardinalidad es más complicado. No podemos simplemente aumentar el valor TOP
porque el optimizador se dará cuenta de que no devolverá suficientes filas. Sin embargo, podemos usar la MANY()
función para agregar filas a la estimación. Tenga en cuenta que la MANY()
función siempre devolverá 0 filas, pero la estimación de la fila cambia con el parámetro de entrada. Suponga que necesita aumentar la estimación de fila de la tabla derivada en 10X. Una forma de lograr eso:
SELECT
p.Name
, th.ProductId
, th.Quantity
, th.ActualCost
FROM Production.Product p
INNER JOIN (
SELECT TOP (9223372036854775807) ProductId, Quantity, ActualCost
FROM Production.TransactionHistory
LEFT OUTER JOIN dbo.Many(10) AS m ON 1=1
) th ON p.ProductID = th.ProductID;
Podemos ver que la estimación es 10 veces la tabla base:
Se TOP
agregó lo superfluo para evitar que el optimizador mueva las tablas. Sin ella, la MANY()
función puede aplicarse al lugar equivocado en el plan.
Es posible combinar las dos técnicas si desea una sobreestimación precisa en lugar de simplemente multiplicar el número de filas por un factor. Por ejemplo, supongamos que realmente necesita que la estimación de la tabla derivada sea exactamente de 1000000 filas. Una forma de lograr eso:
DECLARE @row_goal BIGINT = 9223372036854775807;
SELECT
p.Name
, th.ProductId
, th.Quantity
, th.ActualCost
FROM Production.Product p
INNER JOIN (
SELECT TOP (@row_goal) ProductId, Quantity, ActualCost
FROM Production.TransactionHistory
LEFT OUTER JOIN dbo.Many(10) AS m ON
1=1
) th ON p.ProductID = th.ProductID
OPTION (OPTIMIZE FOR (@row_goal = 1000000));
Podemos ver que la estimación es de 1000000 filas:
Debo advertirle que estas son técnicas avanzadas que a menudo no son necesarias para la optimización de consultas. Si desea obtener más información, le recomiendo ver Choque de los objetivos de la fila presentado por Adam Machanic.
dbo.Mucha función
-- By Adam Machanic, reproduced with permission
IF EXISTS (SELECT * FROM sys.objects WHERE name = 'Many' AND OBJECT_SCHEMA_NAME(object_id) = 'dbo')
DROP FUNCTION dbo.Many
GO
CREATE FUNCTION dbo.Many(@n INT)
RETURNS TABLE AS
RETURN
(
WITH
a(x) AS
(
SELECT
*
FROM
(
VALUES
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)
) AS x0(x)
)
SELECT TOP(@n)
1 AS x
FROM
a AS a1,
a AS a2
WHERE
a1.x % 2 = 0
)
GO