เหตุใดแบบสอบถามรวมจึงเร็วขึ้นอย่างมากเมื่อใช้ GROUP BY clause มากกว่าไม่มี


12

ฉันแค่อยากรู้ว่าเหตุใดแบบสอบถามโดยรวมจึงทำงานเร็วขึ้นมากโดยมีGROUP BYประโยคมากกว่าไม่มี

ตัวอย่างเช่นแบบสอบถามนี้ใช้เวลาเกือบ 10 วินาทีในการเรียกใช้

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1

ในขณะนี้อันนี้ใช้เวลาน้อยกว่าหนึ่งวินาที

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate

มีเพียงหนึ่งเดียวCreatedDateในกรณีนี้ดังนั้นคิวรีที่จัดกลุ่มจะส่งคืนผลลัพธ์เดียวกับกลุ่มที่ไม่ได้จัดกลุ่ม

ฉันสังเกตเห็นแผนการดำเนินการสำหรับแบบสอบถามที่สองจะแตกต่างกัน - แบบสอบถามที่สองใช้ Parallelism ในขณะที่แบบสอบถามแรกไม่

แผนปฏิบัติการ Query1 แผนปฏิบัติการ Query2

เป็นเรื่องปกติหรือไม่ที่เซิร์ฟเวอร์ SQL จะประเมินคิวรีแบบรวมแตกต่างกันถ้ามันไม่มี GROUP BY clause? และมีสิ่งที่ฉันสามารถทำได้เพื่อปรับปรุงประสิทธิภาพของแบบสอบถามที่ 1 โดยไม่ต้องใช้GROUP BYคำสั่งหรือไม่

แก้ไข

ฉันเพิ่งเรียนรู้ว่าฉันสามารถใช้OPTION(querytraceon 8649)ในการตั้งค่าใช้จ่ายค่าใช้จ่ายของความเท่าเทียมเป็น 0 ซึ่งทำให้แบบสอบถามใช้ความเท่าเทียมและลดรันไทม์เป็น 2 วินาทีแม้ว่าฉันจะไม่รู้ว่ามีข้อเสียในการใช้คำใบ้แบบสอบถามนี้หรือไม่

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
OPTION(querytraceon 8649)

ป้อนคำอธิบายรูปภาพที่นี่

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

SELECT Min(CreatedDate)
FROM
(
    SELECT Min(CreatedDate) as CreatedDate
    FROM MyTable WITH (NOLOCK) 
    WHERE SomeIndexedValue = 1
    GROUP BY CreatedDate
) as T

แก้ไข # 2

เพื่อตอบสนองต่อคำขอของ Martin สำหรับข้อมูลเพิ่มเติม :

ทั้งคู่CreatedDateและSomeIndexedValueมีดัชนีที่ไม่ซ้ำกันและไม่ทำคลัสเตอร์แยกต่างหาก SomeIndexedValueจริง ๆ แล้วเป็นฟิลด์ varchar (7) แม้ว่ามันจะเก็บค่าตัวเลขที่ชี้ไปที่ PK (int) ของตารางอื่น ความสัมพันธ์ระหว่างสองตารางไม่ได้กำหนดไว้ในฐานข้อมูล ฉันไม่ควรเปลี่ยนฐานข้อมูลเลยและสามารถเขียนได้เฉพาะแบบสอบถามที่ข้อมูลแบบสอบถาม

MyTableมีมากกว่า 3 ล้านเรคคอร์ดและแต่ละเรคคอร์ดได้รับการจัดกลุ่มเป็นของ ( SomeIndexedValue) กลุ่มสามารถอยู่ที่ใดก็ได้ตั้งแต่ 1 ถึง 200,000 รายการ

คำตอบ:


8

ดูเหมือนว่าอาจเป็นไปตามดัชนีCreatedDateในลำดับจากต่ำสุดไปหาสูงสุดและทำการค้นหาเพื่อประเมินเพSomeIndexedValue = 1รดิเคต

เมื่อพบแถวแรกที่จับคู่เสร็จแล้ว แต่อาจทำการค้นหาได้มากกว่าที่คาดไว้ก่อนที่จะพบแถวดังกล่าว (สมมติว่าแถวที่ตรงกับภาคแสดงมีการกระจายแบบสุ่มตามวันที่)

ดูคำตอบของฉันที่นี่สำหรับปัญหาที่คล้ายกัน

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

SELECT MIN(DATEADD(DAY, 0, CreatedDate)) AS CreatedDate
FROM MyTable
WHERE SomeIndexedValue = 1

เพื่อป้องกันไม่ให้ใช้แผนเฉพาะนั้น


2

เราสามารถควบคุม MAXDOP และเลือกตารางที่รู้จักเช่น AdventureWorks.Production.TransactionHistory ได้หรือไม่?

เมื่อฉันตั้งค่าของคุณซ้ำโดยใช้

--#1
SELECT MIN(TransactionDate) 
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
OPTION( MAXDOP 1) ;

--#2
SELECT MIN(TransactionDate) 
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO 

ค่าใช้จ่ายเหมือนกัน

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

ตัวอย่าง (ฉันไม่ใช้ MIN เนื่องจากไม่ได้ทำงานในมุมมองที่จัดทำดัชนี):

USE AdventureWorks ;
GO

-- Covering Index with Include
CREATE INDEX IX_CoverAndInclude
ON Production.TransactionHistory(TransactionDate) 
INCLUDE (Quantity) ;
GO

-- Indexed View
CREATE VIEW dbo.SumofQtyByTransDate
    WITH SCHEMABINDING
AS
SELECT 
      TransactionDate 
    , COUNT_BIG(*) AS NumberOfTransactions
    , SUM(Quantity) AS TotalTransactions
FROM Production.TransactionHistory
GROUP BY TransactionDate ;
GO

CREATE UNIQUE CLUSTERED INDEX SumofAllChargesIndex 
    ON dbo.SumofQtyByTransDate (TransactionDate) ;  
GO


--#1
SELECT SUM(Quantity) 
FROM AdventureWorks.Production.TransactionHistory 
WITH (INDEX(0))
WHERE TransactionID = 100001 
OPTION( MAXDOP 1) ;

--#2
SELECT SUM(Quantity)  
FROM AdventureWorks.Production.TransactionHistory 
WITH (INDEX(IX_CoverAndInclude))
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO 

--#3
SELECT SUM(Quantity)  
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO

MAXDOPกำหนดระดับสูงสุดของความขนานซึ่ง จำกัด จำนวนตัวประมวลผลที่สามารถใช้แบบสอบถามได้ สิ่งนี้จะทำให้แบบสอบถามที่ 2 รันช้ากว่าแบบสอบถามที่ 1 เนื่องจากเป็นการลบความสามารถในการใช้ขนานซึ่งไม่ใช่สิ่งที่ฉันต้องการ
Rachel

@ ราเชลฉันเห็นด้วย; แต่เราไม่สามารถเปรียบเทียบอะไรได้นอกจากเราจะตั้งกฎพื้นฐานไว้บ้าง ฉันไม่สามารถเปรียบเทียบกระบวนการแบบขนานที่ทำงานบน 64 คอร์กับเธรดเดี่ยวที่ทำงานอย่างเดียวได้อย่างง่ายดาย ในท้ายที่สุดฉันหวังว่าเครื่องของเราทุกเครื่องจะมี CPU อย่างน้อยหนึ่งโลจิคัล = -)
ooutwire

0

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

ฉันได้เห็นสถานการณ์มากมายที่การเขียนแบบสอบถามใหม่ในรูปแบบที่แตกต่างกันคือความแตกต่างระหว่างการทำให้เป็นคู่ (ตัวอย่างเช่นแม้ว่าบทความส่วนใหญ่เกี่ยวกับ SQL แนะนำให้ทำพารามิเตอร์ฉันพบว่ามันทำให้บางครั้ง Noy ให้ขนานกันแม้ว่าพารามิเตอร์ sniffed - ขนานหนึ่งหรือรวมสองแบบสอบถามกับ UNION ALL บางครั้งสามารถกำจัดขนาน

เช่นวิธีแก้ไขที่ถูกต้องอาจลองวิธีการเขียนแบบสอบถามต่าง ๆ เช่นลอง temp tables, table table, cte, table ที่ได้รับ, parameterizing และอื่น ๆ และยังเล่นกับ index, index view หรือ indexed filter ใน เพื่อให้ได้แผนที่ดีที่สุด

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