เรียงลำดับที่ระบุในคีย์หลัก แต่การเรียงลำดับจะถูกดำเนินการบน SELECT


15

ฉันจัดเก็บข้อมูลเซ็นเซอร์ในตารางSensorValues ตารางและคีย์หลักมีดังนี้:

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

แต่เมื่อฉันเลือกค่าเซ็นเซอร์ที่ถูกต้องในเวลาที่กำหนดแผนการดำเนินการบอกฉันว่ามันกำลังทำการเรียงลำดับ ทำไมถึงเป็นอย่างนั้น?

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

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

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

แก้ไข: ฉันสามารถทำสิ่งนี้แทนได้หรือไม่

เนื่องจากตารางเป็นเรียงDeviceID, SensorId วันและฉันทำSELECTระบุเพียงหนึ่งDeviceIDและเป็นหนึ่งในSensorIdชุดที่ส่งออกควรจะเรียงแล้วโดยวันที่ DESC ดังนั้นฉันสงสัยว่าคำถามต่อไปนี้จะให้ผลลัพธ์เดียวกันในทุกกรณีหรือไม่

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

ตาม @Catcall ด้านล่างลำดับการจัดเรียงนั้นไม่เหมือนกับใบสั่งจัดเก็บ นั่นคือเราไม่สามารถสรุปได้ว่าค่าที่ส่งคืนนั้นเรียงตามลำดับแล้ว

แก้ไข: ฉันได้ลองใช้โซลูชัน CROSS นี้แล้วไม่มีโชค

@ มาร์ตินสมิ ธ แนะนำให้ฉันลองนำผลของฉันไปเปรียบเทียบกับพาร์ติชั่น ฉันพบโพสต์บล็อก ( จัดทำดัชนีที่ไม่ใช่คลัสเตอร์ในตารางที่แบ่งพาร์ติชัน ) อธิบายปัญหาที่คล้ายกันนี้และลองวิธีแก้ปัญหาที่คล้ายกันบ้างกับสิ่งที่ Smith แนะนำ อย่างไรก็ตามไม่มีโชคที่นี่เวลาดำเนินการเสมอกับโซลูชันดั้งเดิมของฉัน

WITH Boundaries(boundary_id)
AS
(
  SELECT boundary_id
  FROM sys.partition_functions pf
  JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
  WHERE pf.name = 'PF'
  AND prf.value <= 1339225010
  UNION ALL
  SELECT max(boundary_id) + 1
  FROM sys.partition_functions pf
  JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
  WHERE pf.name = 'PF'
  AND prf.value <= 1339225010
),
Top1(SensorValue)
AS
(
  SELECT TOP 1 d.SensorValue
  FROM Boundaries b
  CROSS APPLY
  (
    SELECT TOP 1 SensorValue
      FROM SensorValues
      WHERE  SensorId = 53
        AND DeviceId = 3819
        AND "Date" < 1339225010
        AND $Partition.PF(Date) = b.boundary_id
        ORDER BY Date DESC
  ) d
  ORDER BY d.Date DESC
)
SELECT SensorValue
FROM Top1

OPTION MAXDOP 1 ไม่ช่วย ตามที่ระบุโดยสมิ ธ @ Martin ด้านล่างมันดูเหมือนกับการแบ่งเป็นสิ่งที่ก่อให้เกิดมัน ...
m__

คำตอบ:


13

สำหรับตารางที่ไม่ได้แบ่งพาร์ติชันฉันจะได้รับแผนต่อไปนี้

แผน 1

มีการแสวงหาคำกริยาSeek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010เดียว

หมายความว่า SQL Server สามารถทำการค้นหาที่เท่าเทียมกันในสองคอลัมน์แรกและจากนั้นเริ่มช่วงการค้นหาที่เริ่มต้น1339225010และสั่งซื้อFORWARD(ตามที่ดัชนีถูกกำหนดด้วย[Date] DESC)

TOPผู้ประกอบการจะหยุดขอเพิ่มเติมจากแถวเสาะหาแถวแรกถูกปล่อยออกมา

เมื่อฉันสร้างรูปแบบพาร์ทิชันและฟังก์ชั่น

CREATE PARTITION FUNCTION PF (int)
AS RANGE LEFT FOR VALUES (1000, 1339225009 ,1339225010 , 1339225011);
GO
CREATE PARTITION SCHEME [MyPartitioningScheme]
AS PARTITION PF
ALL TO ([PRIMARY] );

และเติมตารางด้วยข้อมูลต่อไปนี้

INSERT INTO [dbo].[SensorValues]    
/*500 rows matching date and SensorId, DeviceId predicate*/
SELECT TOP (500) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))           
FROM master..spt_values
UNION ALL
/*700 rows matching date but not SensorId, DeviceId predicate*/
SELECT TOP (700) 3819,52,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))           
FROM master..spt_values
UNION ALL 
/*1100 rows matching SensorId, DeviceId predicate but not date */
SELECT TOP (1100) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) + 1339225011      
FROM master..spt_values

แผนบน SQL Server 2008 มีลักษณะดังนี้

แผน 2

500จำนวนที่แท้จริงของแถวที่ปล่อยออกมาจากแสวงหาก็คือ แผนแสดงแสวงหาภาคแสดง

Seek Keys[1]: Start: PtnId1000 <= 2, End: PtnId1000 >= 1, 
Seek Keys[2]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010

บ่งชี้ว่ามีการใช้เฮี๊ยบสแกนวิธีการอธิบายไว้ที่นี่

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

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

ในความเป็นจริงแผนในปี 2005 ดูเหมือนว่าจะใช้วิธีการที่

แผนในปี 2005

ผมไม่แน่ใจว่าถ้ามันเป็นตรงไปตรงมาเพื่อให้ได้แผนเดียวกันใน 2008 หรือบางทีมันอาจจะต้องใช้OUTER APPLYในsys.partition_range_valuesการจำลองการมัน



9

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

ตัวอย่างเช่นดูโพสต์บล็อกนี้และการสนทนาที่ยาวนานขึ้น


1
ก่อนหน้านี้ OP ยังกล่าวอีกว่า "ฉันคิดว่าตั้งแต่ฉันเก็บค่าที่เรียงตามคอลัมน์วันที่การเรียงลำดับจะไม่เกิดขึ้น [sic]" อย่างน้อยก็ส่วนหนึ่งของปัญหาคือความเข้าใจผิดเกี่ยวกับสิ่งที่ดัชนีคลัสเตอร์ทำ ฉันคิดว่ามันเป็นเรื่องดีที่จะยืดออก
Mike Sherrill 'Cat Recall'

บางทีฉันอาจจะดื้อรั้น (โปรดยกโทษให้ฉันด้วย ;-)) ยังไงก็ตามฉันได้อ่านบล็อกโพสต์โดย Hugo Kornelis และมันค่อนข้างตรงไปตรงมา อย่างไรก็ตามในตัวอย่างของเขาเขากำลังใช้ดัชนีคลัสเตอร์หนึ่งรายการและไม่ใช่คลัสเตอร์หนึ่งดัชนีที่ไม่ใช่คลัสเตอร์จะมีขนาดเล็กลงและจะถูกใช้ในแผนการดำเนินการ ในกรณีของฉันฉันมีดัชนีคลัสเตอร์เดียวเท่านั้นเซิร์ฟเวอร์ sql สามารถยังคงส่งคืนค่าในลำดับที่ไม่ถูกต้อง (มันไม่มีดัชนีขนาดเล็กกว่าที่จะใช้และการสแกนตารางเต็มช้าเกินไป)
m__

ฉันย้ายคำถามนี้ไปเป็นคำถามใหม่ (ปิดหัวข้อ)
m__

5

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

ดังนั้นลองใช้ MAXDOP 1 และดูว่าเกิดอะไรขึ้น ...

ยังมีคำใบ้ในบล็อกของ @sql kiwi ใน Simple Talkภายใต้ "Exchange Operator" และ"การพึ่งพา DOP" ที่นี่


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

1

โดยทั่วไปคุณมีสิทธิ์ - เนื่องจากคีย์หลักอยู่ในลำดับ "DeviceId, SensorId, Date" ข้อมูลในคีย์จะไม่เรียงตามวันที่ดังนั้นจึงไม่สามารถใช้งานได้ หากคีย์ของคุณอยู่ในลำดับ "Date, DeviceId, SensorId" ที่แตกต่างกันดังนั้นข้อมูลในคีย์จะเรียงลำดับตามวันที่ดังนั้นจึงสามารถใช้ ...


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