เขตข้อมูลจากการคำนวณ SQL ในทั้ง SELECT และ GROUP BY clause


11

บ่อยครั้งในการสืบค้นฐานข้อมูล MS SQL Server ของฉันฉันต้องสร้างเขตข้อมูลจากการคำนวณเช่นนี้

(CASE WHEN A.type = 'Workover' THEN 'Workover' 
      ELSE (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' 
                 WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' 
                 WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' 
                 ELSE 'Other' 
            END)
END)

จากนั้นฉันต้องจัดกลุ่มผลลัพธ์ของฉันตามฟิลด์ที่คำนวณนี้ (อื่น ๆ ) ดังนั้นฉันมีการคำนวณที่เหมือนกันทั้งใน SELECT และ GROUP BY clauses เซิร์ฟเวอร์ SQL ทำการคำนวณเหล่านี้สองครั้งจริง ๆ หรือฉลาดพอที่จะทำเพียงครั้งเดียวหรือไม่

คำตอบ:


13

ฉันมีการคำนวณเหมือนกันทั้งใน SELECT และ GROUP BY clauses เซิร์ฟเวอร์ SQL ทำการคำนวณเหล่านี้สองครั้งจริง ๆ หรือฉลาดพอที่จะทำเพียงครั้งเดียวหรือไม่

คำตอบง่ายๆคือ SQL Server ไม่รับประกันโดยทั่วไปเกี่ยวกับเวลาและจำนวนครั้งที่นิพจน์สเกลาร์จะถูกประเมินเมื่อทำการประมวลผล

มีพฤติกรรมที่ซับซ้อน (และไม่มีเอกสาร) ในเครื่องมือเพิ่มประสิทธิภาพและเครื่องมือดำเนินการที่เกี่ยวข้องกับการจัดวางการดำเนินการและการแคชสเกลานิพจน์ Books Online ไม่มีอะไรจะพูดเกี่ยวกับสิ่งนี้มากนัก แต่สิ่งที่กล่าวมาคือ:

คำนวณรายละเอียดเกลา

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

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

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

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

หากคุณพบกรณีที่ปัญหาการประเมินสเกลาร์มีความสำคัญต่อประสิทธิภาพให้เพิ่มปัญหาด้วยฝ่ายสนับสนุนของ Microsoft นี่เป็นวิธีที่ดีที่สุดในการให้ข้อเสนอแนะเพื่อปรับปรุงผลิตภัณฑ์ในอนาคต


3

ในขณะที่ความคิดเห็นเกี่ยวกับคำถามของคุณคำตอบคือ (ในประสบการณ์ของฉันอย่างน้อย) "ใช่" SQL Server โดยทั่วไปฉลาดพอที่จะหลีกเลี่ยงการคำนวณใหม่ คุณอาจตรวจสอบสิ่งนี้ได้ด้วยการแสดงแผนการดำเนินการจากภายใน SQL Server Management Studio แต่ละฟิลด์จากการคำนวณถูกกำหนดExprxxxxx(โดยที่ xxxxx เป็นตัวเลข) หากคุณรู้ว่าจะต้องหาอะไรคุณควรจะสามารถยืนยันได้ว่ามันใช้สำนวนเดียวกัน

เพื่อเพิ่มการสนทนาตัวเลือกสุนทรียะอื่น ๆ ของคุณคือนิพจน์ตารางทั่วไป :

with [cte] as
(
    select
        (case when a.type = 'workover' then 'workover' else 
        (case when substring(c.category, 2, 1) = 'd' then 'drilling'
              when substring(c.category, 2, 1) = 'c' then 'completion'
              when substring(c.category, 2, 1) = 'w' then 'workover'
              else 'other' end)
         end)) as [group_key],
         *
    from
        [some_table]
)
select
    [group_key],
    count(*) as [count]
from
    [cte]
group by
    [group_key]

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

แม้ว่าจะไม่เกี่ยวข้องกับคำถามนี้พวกเขาสามารถอ้างถึงตัวเองและใช้วิธีนี้เพื่อสร้างแบบสอบถามแบบเรียกซ้ำ


@ Quick Joe Smith: ฉันคิดว่าคุณถูกต้องเกี่ยวกับ Exprxxxxx เพราะฉันก็เห็นเช่นกัน อย่างไรก็ตามถ้าฉันให้ชื่อกับนิพจน์ด้วยตนเอง (case ... end) เป็น OpType ให้ใช้ฟิลด์ OpType ในส่วน GROUP BY clause ฉันได้รับข้อผิดพลาดว่าเป็นชื่อคอลัมน์ที่ไม่ถูกต้อง
ดร. Drew

น่าเสียดายที่บ่อยครั้งที่วิธีการเดียวในการระบุนิพจน์สองครั้งของคุณคือการใช้หนึ่งในวิธีการด้านบน: CTE, มุมมองหรือแบบสอบถามซ้อน
โจสมิ ธ ด่วน

2
เว้นแต่คุณจะรู้เกี่ยวกับCROSSเท่านั้น
Andriy M

การใช้งานcross applyในกรณีนี้เป็นการยืดออกไปเล็กน้อยและอาจเป็นอันตรายต่อประสิทธิภาพการทำงานด้วยการแนะนำตัวเองโดยไม่จำเป็น
โจสมิ ธ อย่างรวดเร็ว

2
ฉันไม่คิดว่าคุณ "ได้รับ" ข้อเสนอแนะ CROSS APPLYเพียงกำหนดนามแฝงจากคอลัมน์ในแถวเดียวกัน ไม่จำเป็นต้องเข้าร่วม เช่นSELECT COUNT(*), hilo FROM master..spt_values CROSS APPLY (VALUES(high + low)) V(hilo) GROUP BY hilo
Martin Smith

1

ประสิทธิภาพเป็นเพียงแง่มุมเดียว อื่น ๆ คือการบำรุงรักษา

ส่วนตัวผมมักจะทำตาม:

SELECT T.GroupingKey, SUM(T.value)
FROM
(
    SELECT 
        A.*
        (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
        (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
        END) AS GroupingKey
    FROM Table AS A
) AS T

GROUP BY T.GroupingKey

UPDATE:

หากคุณไม่ต้องการทำรังคุณสามารถสร้าง VIEW สำหรับแต่ละตารางที่คุณต้องการใช้นิพจน์ที่ซับซ้อน

CREATE VIEW TableExtended
AS 
SELECT 
    A.*
    (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
    (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
    END) AS GroupingKey
FROM Table AS A

จากนั้นคุณสามารถเลือกโดยไม่ต้องทำรังพิเศษ

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