คุณสามารถได้รับสิ่งที่คล้ายกับCARDINALITY
คำใบ้ของ Oracle โดยใช้กลยุทธ์TOP
และฟังก์ชั่นที่ผู้ใช้กำหนดเองที่เรียกว่าMANY()
พัฒนาโดย Adam MachanicMachanic มาทำงานกันสองสามตัวอย่าง ฉันใช้ฐานข้อมูล AdventureWorks ที่พร้อมใช้งานได้อย่างอิสระ สมมติว่าฉันต้องการควบคุมจำนวนแถวที่ส่งคืนโดยth
ตารางที่ได้รับในแบบสอบถามต่อไปนี้:
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;
ตามที่ฉันได้รับประมาณ 113,443 แถว:
หากฉันต้องการลดค่าประมาณจากth
ฉันสามารถใช้TOP
พร้อมกับOPTIMIZE FOR
คำใบ้เพื่อตั้งค่าเป้าหมายแถว นี่เป็นวิธีหนึ่งในการทำ:
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));
เราจะเห็นว่าค่าประมาณเป็นเพียง 1 แถว:
ฉันตั้งค่า@row_goal
ให้ใหญ่ที่สุดเท่าที่จะเป็นไปได้BIGINT
เพื่อหลีกเลี่ยงการเปลี่ยนแปลงผลลัพธ์ OPTIMIZE FOR
คำแนะนำการสอบถามสั่งให้เพิ่มประสิทธิภาพในการเพิ่มประสิทธิภาพการค้นหาเช่นถ้า@row_goal
มีค่าเท่ากับ 1 ฉันจะได้รับผลเหมือนกัน แต่แบบสอบถามจะถูกปรับที่แตกต่างกัน
การเพิ่มค่าประมาณความเป็น cardinality นั้นยากกว่า เราไม่สามารถเพิ่มมูลค่าTOP
เพราะเครื่องมือเพิ่มประสิทธิภาพจะรู้ว่าจะไม่ส่งคืนแถวมากพอ อย่างไรก็ตามเราสามารถใช้MANY()
ฟังก์ชันเพื่อเพิ่มแถวในการประมาณ โปรดทราบว่าMANY()
ฟังก์ชั่นจะส่งคืน 0 แถวเสมอ แต่การประมาณแถวจากนั้นจะเปลี่ยนไปตามพารามิเตอร์อินพุต สมมติว่าคุณต้องการเพิ่มการประมาณแถวจากตารางที่ได้รับ 10X วิธีหนึ่งที่จะทำให้สำเร็จ:
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;
เราจะเห็นว่าค่าประมาณ 10X เป็นตารางพื้นฐาน:
ความฟุ่มเฟือย TOP
เพื่อป้องกันไม่ให้เครื่องมือเพิ่มประสิทธิภาพการย้ายตารางรอบ ๆ ก็ไม่มีMANY()
ฟังก์ชั่นสามารถนำไปใช้กับสถานที่ที่ไม่ถูกต้องในแผน
เป็นไปได้ที่จะรวมเทคนิคทั้งสองเข้าด้วยกันหากคุณต้องการให้ประเมินค่าสูงไปอย่างแม่นยำแทนที่จะคูณจำนวนแถวด้วยตัวคูณ ตัวอย่างเช่นสมมติว่าคุณต้องการค่าประมาณของตารางที่ได้รับเป็น 1000000 แถว วิธีหนึ่งที่จะทำให้สำเร็จ:
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));
เราจะเห็นว่าค่าประมาณ 1000000 แถว:
ฉันต้องเตือนคุณว่านี่เป็นเทคนิคขั้นสูงซึ่งมักไม่จำเป็นสำหรับการปรับให้เหมาะสมของแบบสอบถาม หากคุณต้องการเรียนรู้เพิ่มเติมฉันขอแนะนำให้ดูการแข่งขันClash of the Row Goalsโดย Adam Machanic
dbo ฟังก์ชั่นมากมาย
-- 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