ปรับดัชนีให้เหมาะสมบนตารางแถว 2,135,044,521


10

ฉันมีปัญหา I / O กับตารางขนาดใหญ่

สถิติทั่วไป

ตารางมีลักษณะสำคัญดังต่อไปนี้:

  • สภาพแวดล้อม: ฐานข้อมูล Azure SQL (ระดับชั้นเป็น P4 พรีเมียม (500 DTU))
  • แถว: 2,135,044,521
  • พาร์ติชันที่ใช้ 1,275
  • ดัชนีคลัสเตอร์และพาร์ติชัน

แบบ

นี่คือการใช้ตาราง:

CREATE TABLE [data].[DemoUnitData](
    [UnitID] [bigint] NOT NULL,
    [Timestamp] [datetime] NOT NULL,
    [Value1] [decimal](18, 2) NULL,
    [Value2] [decimal](18, 2) NULL,
    [Value3] [decimal](18, 2) NULL,
    CONSTRAINT [PK_DemoUnitData] PRIMARY KEY CLUSTERED 
    (
        [UnitID] ASC,
        [Timestamp] ASC
    )
)
GO

ALTER TABLE [data].[DemoUnitData] WITH NOCHECK ADD CONSTRAINT [FK_DemoUnitData_Unit] FOREIGN KEY([UnitID])
REFERENCES [model].[Unit] ([ID])
GO

ALTER TABLE [data].[DemoUnitData] CHECK CONSTRAINT [FK_DemoUnitData_Unit]
GO

การแบ่งพาร์ติชันเกี่ยวข้องกับสิ่งนี้:

CREATE PARTITION SCHEME [DailyPartitionSchema] AS PARTITION [DailyPartitionFunction] ALL TO ([PRIMARY])

CREATE PARTITION FUNCTION [DailyPartitionFunction] (datetime) AS RANGE RIGHT
FOR VALUES (N'2017-07-25T00:00:00.000', N'2017-07-26T00:00:00.000', N'2017-07-27T00:00:00.000', ... )

คุณภาพของการบริการ

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

นี่คือสถิติดัชนีปัจจุบันของพาร์ติชันดัชนีที่ใช้งานมากที่สุด:

สถิติการแบ่งพาร์ติชัน

นี่คือคุณสมบัติสถิติปัจจุบันของพาร์ติชันที่ใช้งานหนักที่สุด:

สถิติ

ปัญหา

ฉันเรียกใช้แบบสอบถามอย่างง่าย ๆ ที่มีความถี่สูงเทียบกับตาราง

SELECT [UnitID]
    ,[Timestamp]
    ,[Value1]
    ,[Value2]
    ,[Value3]
FROM [data].[DemoUnitData]
WHERE [UnitID] = 8877 AND [Timestamp] >= '2018-03-01' AND [Timestamp] < '2018-03-13'
OPTION (MAXDOP 1)

นับ exce

แผนการดำเนินการมีลักษณะดังนี้: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG

ปัญหาของฉันคือแบบสอบถามเหล่านี้ผลิตการดำเนินงาน I / O จำนวนมากอย่างมากซึ่งส่งผลให้เกิดปัญหาการPAGEIOLATCH_SHรอคอย

รอด้านบน

คำถาม

ฉันได้อ่านแล้วว่าการPAGEIOLATCH_SHรอนั้นมักจะเกี่ยวข้องกับดัชนีที่ไม่เหมาะสม มีคำแนะนำใดที่คุณมีสำหรับฉันในการลดการทำงานของ I / O หรือไม่? อาจจะโดยการเพิ่มดัชนีที่ดีกว่า


คำตอบ 1 - เกี่ยวข้องกับความคิดเห็นจาก @ S4V1N

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

(@p__linq__0 bigint,@p__linq__1 datetime2(7),@p__linq__2 datetime2(7)) 

SELECT 1 AS [C1], [Extent1] 
   .[Timestamp] AS [Timestamp], [Extent1] 
   .[Value1] AS [Value1], [Extent1] 
   .[Value2] AS [Value2], [Extent1] 
   .[Value3] AS [Value3]  
FROM [data].[DemoUnitData] AS [Extent1]  
WHERE ([Extent1].[UnitID] = @p__linq__0)  
AND ([Extent1].[Timestamp] >= @p__linq__1)  
AND ([Extent1].[Timestamp] < @p__linq__2) OPTION (MAXDOP 1) 

นอกจากนี้แผนยังดูแตกต่าง:

https://www.brentozar.com/pastetheplan/?id=H1fhALpKG

หรือ

https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz

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

SQL อันดับสูงสุด

คำตอบ 2 - เกี่ยวข้องกับคำตอบจาก @Joe Obbish

สำหรับการทดสอบโซลูชันฉันแทนที่ Entity Framework ด้วย SqlCommand อย่างง่าย ผลที่ได้คือการเพิ่มประสิทธิภาพที่น่าทึ่ง!

แผนแบบสอบถามขณะนี้เหมือนกับใน SSMS และตรรกะอ่านและเขียนปล่อยไป ~ 8 ต่อการดำเนินการ

โหลด I / O โดยรวมลดลงเกือบ 0! I / O ลดลง

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


2
เมื่อดูที่แผนการดำเนินการแบบสอบถามนั้นดูเหมือนจะไม่เป็นปัญหา แต่อย่างใดมันได้สแกนเฉพาะพาร์ติชั่นที่จำเป็นที่มีจำนวนการอ่านน้อยและไม่ได้รายงานว่ามีการรอ Pageiolatch_sh (sos_sched .. ) แทน สิ่งใดที่เข้าใจได้เพราะคุณไม่ได้อ่านหนังสือ การสะสมเหล่านั้นจะรอคอยหรือถูกยึดครองในช่วงระยะเวลาหนึ่งหรือไม่? อาจมีปัญหาคือแบบสอบถามอื่น ๆ หลังจากทั้งหมด
S4V1N

ฉันโพสต์คำตอบโดยละเอียดกับคุณ @ S4V1N ด้านบน
Steffen Mangold

คำตอบ:


7

คุณอาจลดการPAGEIOLATCH_SHรอคิวรีนี้ได้ถ้าคุณสามารถเปลี่ยนประเภทข้อมูลที่สร้างโดย ORM Timestampคอลัมน์ในตารางของคุณมีชนิดข้อมูลของDATETIMEแต่พารามิเตอร์@p__linq__1และมีชนิดของข้อมูล@p__linq__2 DATETIME2(7)ความแตกต่างนั่นคือเหตุผลที่แผนแบบสอบถามสำหรับแบบสอบถาม ORM นั้นซับซ้อนกว่าแผนแบบสอบถามแรกที่คุณโพสต์ที่มีตัวกรองการค้นหาแบบฮาร์ดโค้ด คุณสามารถหาคำแนะนำใน XML ได้เช่นกัน:

<ScalarOperator ScalarString="GetRangeWithMismatchedTypes([@p__linq__1],NULL,(22))">

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

ฉันทำซ้ำง่าย ๆ เพื่อให้แน่ใจ พาร์ติชั่นมี 11 พาร์ติชั่นที่กำหนดไว้ในฟังก์ชันพาร์ติชั่น สำหรับการค้นหานี้:

DECLARE @p__linq__0 bigint = 2000;
DECLARE @p__linq__1 datetime2(7) = '20180103';
DECLARE @p__linq__2 datetime2(7) = '20180104';

SELECT 1 AS [C1]
, [Extent1].[Timestamp] AS [Timestamp]
, [Extent1].[Value1] AS [Value1]
FROM [DemoUnitData] AS [Extent1]  
WHERE ([Extent1].[UnitID] = @p__linq__0)  
AND ([Extent1].[Timestamp] >= @p__linq__1)  
AND ([Extent1].[Timestamp] < @p__linq__2)
OPTION (MAXDOP 1) ;

นี่คือลักษณะของ IO:

ตาราง 'DemoUnitData' จำนวนการสแกน 11, ตรรกะอ่าน 40

เมื่อฉันแก้ไขประเภทข้อมูล:

DECLARE @p__linq__0 bigint = 2000;
DECLARE @p__linq__1 datetime = '20180103';
DECLARE @p__linq__2 datetime = '20180104';

SELECT 1 AS [C1]
, [Extent1].[Timestamp] AS [Timestamp]
, [Extent1].[Value1] AS [Value1]
FROM [DemoUnitData] AS [Extent1]  
WHERE ([Extent1].[UnitID] = @p__linq__0)  
AND ([Extent1].[Timestamp] >= @p__linq__1)  
AND ([Extent1].[Timestamp] < @p__linq__2)
OPTION (MAXDOP 1) ;

IO ลดลงเนื่องจากการกำจัดพาร์ติชัน:

ตาราง 'DemoUnitData' สแกนจำนวน 2, ตรรกะอ่าน 8

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