หาก CTE ถูกกำหนดในแบบสอบถามและไม่เคยใช้มันจะส่งเสียงหรือไม่?


32

CTE ที่ไม่ได้ใช้งานในคิวรีส่งผลต่อประสิทธิภาพและ / หรือเปลี่ยนแผนคิวรีที่สร้างขึ้นหรือไม่

คำตอบ:


21

ไม่ปรากฏว่าพวกเขาทำ แต่สิ่งนี้ใช้ได้กับ CTE ที่ซ้อนกันเท่านั้น

สร้างตารางชั่วคราวสองตาราง:

CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );

CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );

แบบสอบถาม 1:

WITH your_mom AS (
    SELECT TOP 1 *
    FROM #t1 AS t 
),
also_your_mom AS (
    SELECT TOP 1 *
    FROM #t2 AS t
)
SELECT *
FROM your_mom;

แบบสอบถาม 2:

WITH your_mom AS (
    SELECT TOP 1 *
    FROM #t1 AS t 
),
also_your_mom AS (
    SELECT TOP 1 *
    FROM #t2 AS t
)
SELECT *
FROM also_your_mom;

แผนการค้นหา:

ถั่ว

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


28

+1 ใน Erik แต่ต้องการเพิ่มสองสิ่ง (ซึ่งทำงานได้ไม่ดีในความคิดเห็น):

  1. คุณไม่จำเป็นต้องดูที่แผนปฏิบัติการเพื่อดูว่ามันถูกเพิกเฉยเมื่อไม่ได้ใช้งาน ต่อไปนี้ควรสร้างข้อผิดพลาด "หารด้วย 0" แต่ไม่ได้เนื่องจากcte2ไม่ได้ถูกเลือกจากเลย:

    ;WITH cte1 AS
    (
      SELECT 1 AS [Bob]
    ),
    cte2 AS (
      SELECT 1 / 0 AS [Err]
      FROM cte1
    )
    SELECT *
    FROM   cte1;
  2. สามารถละเว้น CTE แม้ว่าจะเป็น CTE เดียวเท่านั้นและแม้ว่าจะถูกเลือกจากหากมีเหตุผลทุกแถวจะถูกยกเว้น ต่อไปนี้เป็นกรณีที่เคียวรีเครื่องมือเพิ่มประสิทธิภาพทราบล่วงหน้าว่าจะไม่มีแถวใดสามารถส่งคืนจาก CTE ได้ดังนั้นจึงไม่ต้องกังวลที่จะเรียกใช้งาน:

    ;WITH cte AS
    (
      SELECT 1 / 0 AS [Bob]
    )
    SELECT TOP (1) [object_id]
    FROM   sys.objects
    UNION ALL
    SELECT cte.[Bob]
    FROM   cte
    WHERE  1 = 0;

เกี่ยวกับประสิทธิภาพ CTE ที่ไม่ได้ใช้จะถูกวิเคราะห์และเรียบเรียง (หรือรวบรวมอย่างน้อยในกรณีด้านล่าง) ดังนั้นจึงไม่ได้ถูกเพิกเฉย 100% แต่ค่าใช้จ่ายจะต้องไม่สำคัญและไม่คุ้มค่าที่จะกังวล

เมื่อแยกวิเคราะห์เท่านั้นไม่มีข้อผิดพลาด:

SET PARSEONLY ON;

;WITH cte1 AS
(
  SELECT obj.[NotHere]
  FROM   sys.objects obj
)
SELECT TOP (1) so.[name]
FROM   sys.objects so

GO
SET PARSEONLY OFF;
GO

เมื่อทำทุกสิ่งที่ขาดการปฏิบัติก็มีปัญหา:

GO
SET NOEXEC ON;
GO

;WITH cte1 AS
(
  SELECT obj.[NotHere]
  FROM   sys.objects obj
)
SELECT TOP (1) so.[name]
FROM   sys.objects so

GO
SET NOEXEC OFF;
GO
/*
Msg 207, Level 16, State 1, Line XXXXX
Invalid column name 'NotHere'.
*/

หวังว่าฉันจะทำเครื่องหมายคำตอบมากกว่าหนึ่งคำตอบให้ถูกต้อง แต่เอริคเอาชนะคุณให้ปืนพกดึง :) แต่คำตอบของคุณนั้นให้ข้อมูลและยอดเยี่ยมเช่นกันขอบคุณ!
JD

จะเป็นอย่างไรถ้า CTE อยู่ในมุมมองและมุมมองซ้อนกันมากกว่า 3 ครั้ง ไม่มีจุดที่เครื่องมือเพิ่มประสิทธิภาพยอมแพ้และทำงานทั้งหมดหรือไม่
Zikato

@Zikato ฉันไม่รู้ แต่นั่นเป็นคำถามที่ดี คุณควรจะสามารถตั้งค่าการทดสอบได้โดยไม่ต้องใช้ความพยายามมากเกินไปโดยการสร้างมุมมองโดยใช้การหารด้วยเลขศูนย์ที่ฉันได้แสดงไว้ในสองตัวอย่างแรก กรุณาแจ้งให้เราทราบผลลัพธ์ที่ฉันอยากรู้มากตอนนี้เกี่ยวกับสถานการณ์นี้ :-)
โซโลมอน Rutzky

@ SolomonRutzky เพื่อความยุติธรรมฉันได้ทำการทดสอบ แต่มันไม่ได้ข้อสรุป ฉันได้สร้างมุมมองจากตัวอย่าง cte ของคุณและซ้อนกัน 5 ครั้ง แต่เนื่องจากการสแกนทั้งหมดคงที่และไม่ซับซ้อนจริงๆเครื่องมือเพิ่มประสิทธิภาพจึงจัดการได้ดี ฉันต้องการทดสอบอย่างละเอียดมากขึ้นในอนาคตและซ่อนมันไว้เบื้องหลังตรรกะที่ซับซ้อนมากขึ้น ผมจะแจ้งให้คุณทราบ.
Zikato

@Zikato ที่น่าสนใจ ไม่แน่ใจว่าสิ่งที่จะถูกพิจารณาว่า "ซับซ้อน" แต่ใช่ตัวอย่างของฉันง่ายมาก เมื่อคุณพูดว่า "ซ้อนกัน 5 ครั้ง" คุณหมายถึงในการดู / โพรเซสอื่น ๆ ที่เรียกซึ่งกันและกันและมันเป็น 5 ลึกหรือในเคียวรีย่อย / CTEs? ฉันคิดว่ามีความเป็นไปได้ที่การทำรังในระดับที่มากพออาจข้ามได้ แต่ไม่ใช่เพราะมันไม่ได้ถูกอ้างอิง แต่เนื่องจากระดับรังที่สูงกว่านั้นไม่ได้ใช้ ฉันได้เห็นว่าเคล็ดลับในการวางNEWID()มุมมองเพื่อใช้ใน UDF สามารถส่งคืนค่าเดียวกันจากการโทรหลายครั้งเนื่องจากเครื่องมือเพิ่มประสิทธิภาพการแคช
โซโลมอน Rutzky
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.