คำแนะนำเกี่ยวกับ cardinality ของ SQL Server


14

มีวิธีการ 'ฉีด' การประมาณค่าเชิงปริมาณให้กับเครื่องมือเพิ่มประสิทธิภาพ SQL Server (ทุกรุ่น) หรือไม่?

เช่นสิ่งที่คล้ายกับคำใบ้สำคัญของออราเคิล

แรงจูงใจของฉันถูกขับเคลื่อนโดยบทความเครื่องมือเพิ่มประสิทธิภาพการค้นหาดีแค่ไหนจริงเหรอ? [1]ซึ่งพวกเขาทดสอบอิทธิพลของตัวประมาณความสำคัญต่อการเลือกแผนที่ไม่ดี ดังนั้นมันจะเพียงพอหากฉันสามารถบังคับให้ SQL Server 'ประมาณการ' สำคัญ ๆ อย่างแม่นยำสำหรับการสืบค้นที่ซับซ้อน


[1] Leis, Viktor, et al. "เครื่องมือเพิ่มประสิทธิภาพข้อความค้นหาดีแค่ไหนจริง ๆ "
การดำเนินการของ VLDB Endowment 9.3 (2015): 204-215

คำตอบ:


10

คุณสามารถได้รับสิ่งที่คล้ายกับ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 แถว:

การประมาณ 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 เป็นตารางพื้นฐาน:

แบบสอบถาม 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 แถว:

แถว 1 M

ฉันต้องเตือนคุณว่านี่เป็นเทคนิคขั้นสูงซึ่งมักไม่จำเป็นสำหรับการปรับให้เหมาะสมของแบบสอบถาม หากคุณต้องการเรียนรู้เพิ่มเติมฉันขอแนะนำให้ดูการแข่งขัน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

9

ไม่มีวิธีที่จะฉีดการประมาณค่า cardinality ลงในเครื่องมือเพิ่มประสิทธิภาพโดยตรง แต่ขึ้นอยู่กับสิ่งที่คุณต้องการบรรลุมีตัวเลือกน้อย

คุณสามารถใช้OPTION (FAST N)คำใบ้แบบสอบถามเพื่อแนะนำเป้าหมายของแถวและอาจเขียนคำสืบค้นของคุณใหม่โดยใช้ CTE หรือคิวรีย่อยเพื่อฉีดTOP...ORDER BYเป้าหมายแถวตามในส่วนต่าง ๆ ของแผนปฏิบัติการของคุณ แต่ฉันไม่แน่ใจว่าแบบสอบถามผลลัพธ์ของคุณจะมีประสิทธิภาพอย่างไรเมื่อคุณเริ่ม เล่นรอบกับสิ่งปลูกสร้างที่ซับซ้อนมากขึ้น

ดูภายในเครื่องมือเพิ่มประสิทธิภาพ: แถวเป้าหมายในเชิงลึกเพื่อทราบรายละเอียดเพิ่มเติม

หากคุณต้องการมีอิทธิพลต่อผู้ปฏิบัติงานที่เครื่องมือเพิ่มประสิทธิภาพเลือกคุณไม่จำเป็นต้องพยายามประมาณค่า cardinality แต่คุณสามารถใช้สิ่งต่าง ๆ เช่นOPTION (MERGE JOIN)หรือOPTION (HASH JOIN)ตัวอย่างเพื่อบังคับให้ผู้ประกอบการเข้าร่วมทางกายภาพ

บทความนี้จะกล่าวถึงรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการมีอิทธิพลต่อแผนโดยใช้คำแนะนำ: ควบคุมแผนการดำเนินการด้วยคำแนะนำ

หากคุณต้องการแก้ไขแผนคุณสามารถใช้คำแนะนำแผนได้

อีกครั้งยังไม่ชัดเจนว่ากรณีการใช้งานจริงของคุณคืออะไรและระยะทางของคุณอาจแตกต่างกันไปโดยใช้เทคนิคเหล่านี้ ในหลายกรณีจะเป็นการดีกว่าถ้าให้เครื่องมือเพิ่มประสิทธิภาพตัดสินใจและตรวจสอบให้แน่ใจว่าคุณมีสถิติล่าสุดเพื่อให้เครื่องมือเพิ่มประสิทธิภาพสามารถทำการตัดสินใจอย่างชาญฉลาด


คำแนะนำ Microsoft Connect ที่เกี่ยวข้อง: อนุญาตให้ระบุคำแนะนำการเลือกฟิลเตอร์ในแบบสอบถามโดย xor88 Microsoft ตอบกลับ:

ขอบคุณสำหรับความคิดเห็น. ฉันสามารถเห็นประโยชน์ที่เป็นไปได้ของสิ่งนี้ โดยทั่วไปเราพยายามอย่างหนักเพื่อทำให้พฤติกรรมอัตโนมัติของเราดีที่สุดเท่าที่จะทำได้และหลีกเลี่ยงความต้องการคำใบ้แบบนี้ แต่แน่นอนว่าเรามีคำใบ้อื่น ๆ อีกมากมาย เราจะพิจารณาเรื่องนี้สำหรับการเปิดตัวในอนาคต แต่จะเกินกว่ารุ่น Denali (11.0)

ขอแสดงความนับถือ
Eric Hanson
โปรแกรมจัดการ
การประมวลผลแบบสอบถาม SQL Server


3

คุณสามารถใช้OPTIMIZE FORคำใบ้แบบสอบถามSQL Server เพื่อบีบบังคับการประมาณค่า cardinality ตามค่าที่บอกเป็นนัยแทนการใช้ค่าจริง (พารามิเตอร์) หรือค่าที่ไม่รู้จัก (ตัวแปร) ในระหว่างการรวบรวม ดูหัวข้อคำแนะนำแบบสอบถามในเอกสาร SQL Server สำหรับรายละเอียดทั้งหมด

ตัวอย่างเช่นแบบสอบถามด้านล่างนี้จะประมาณจำนวนแถวตามสถิติฮิสโตแกรมจากค่าที่บอกเป็นนัยแทนที่จะเป็นค่าเฉลี่ยเชิงภาพรวมเช่นเดียวกับตัวแปรท้องถิ่น

DECLARE 
      @StartDate datetime = '20150101'
    , @EndDate datetime = '20150102';
SELECT *
FROM dbo.Example
WHERE
    DateColumn BETWEEN  @StartDate AND @EndDate
OPTION(OPTIMIZE FOR(@StartDate = '20100101', @EndDate='20100101'));

ทำนองเดียวกันอาจใช้คำใบ้สำหรับพารามิเตอร์เพื่อให้การประมาณนั้นอิงตามสถิติฮิสโตแกรมจากค่าที่บอกเป็นนัยแทนที่จะเป็นค่าพารามิเตอร์จริงในระหว่างการรวบรวม

DECLARE 
      @StartDate datetime = '20150101'
    , @EndDate datetime = '20150102';
EXECUTE sp_executesql N'SELECT *
        FROM dbo.Example
        WHERE
            DateColumn BETWEEN  @StartDate AND @EndDate
        OPTION(OPTIMIZE FOR(@StartDate = ''20100101'', @EndDate=''20100101''));'
    , N'@StartDate datetime, @EndDate datetime'
    , @StartDate = @StartDate
    , @EndDate = @EndDate;

UNKNOWNคำหลักอาจจะระบุแทนตัวอักษรในคำแนะนำในการใช้ cardinality เฉลี่ยโดยรวมแทนการประเมินขึ้นอยู่กับค่าพารามิเตอร์ที่เกิดขึ้นจริงและสถิติ histogram

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.