INSERT ที่มีประสิทธิภาพเข้าสู่ตารางที่มีดัชนีเป็นกลุ่ม


28

ฉันมีคำสั่ง SQL ที่แทรกแถวลงในตารางที่มีดัชนีคลัสเตอร์ในคอลัมน์ TRACKING_NUMBER

เช่น:

INSERT INTO TABL_NAME (TRACKING_NUMBER, COLB, COLC) 
SELECT TRACKING_NUMBER, COL_B, COL_C 
FROM STAGING_TABLE

คำถามของฉันคือ - มันช่วยในการใช้คำสั่งย่อย ORDER BY ในคำสั่ง SELECT สำหรับคอลัมน์ดัชนีคลัสเตอร์หรือไม่หรือการได้รับผลประโยชน์ใด ๆ จะได้รับผลกระทบจากการเรียงลำดับพิเศษที่จำเป็นสำหรับคำสั่ง ORDER BY?

คำตอบ:


18

ในฐานะที่เป็นคำตอบอื่น ๆ แล้วบ่งบอกถึง SQL Server insertหรืออาจจะไม่ชัดเจนให้มั่นใจว่าแถวจะเรียงตามลำดับดัชนีคลัสเตอร์ก่อนที่จะมี

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

หากคุณพบว่า SQL Server จะประเมินนี้ด้วยเหตุผลใดก็ตามที่คุณอาจได้รับประโยชน์จากการเพิ่มอย่างชัดเจนORDER BYกับSELECTแบบสอบถามเพื่อลดการแยกหน้าและต่อมาการกระจายตัวจากINSERTการดำเนินงาน

ตัวอย่าง:

use tempdb;

GO

CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))

CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))

GO

DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)

INSERT INTO @T(N)
SELECT number 
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499

/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2

/*Same operation using explicit sort*/    
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;  


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;  

แสดงให้เห็นว่าTมีการแยกส่วนอย่างหนาแน่น

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536             92535                92535                67.1668272794663               250000
99.5                         200                  200                  74.2868173956017               92535
0                            1                    1                    32.0978502594514               200

แต่สำหรับการT2แยกส่วนน้อยที่สุด

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376                        262                  62500                99.456387447492                250000
2.1551724137931              232                  232                  43.2438349394613               62500
0                            1                    1                    37.2374598468001               232

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

DECLARE @var INT =2147483647

INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar

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



12

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

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

แก้ไข: 2011-10-28 17:00

คำตอบของ @Gonsaluปรากฏขึ้นเพื่อแสดงให้เห็นว่าการดำเนินการเรียงลำดับเกิดขึ้นเสมอซึ่งไม่ใช่ในกรณีนี้ ต้องใช้สคริปต์สาธิต!

เมื่อสคริปต์มีขนาดค่อนข้างใหญ่ฉันก็ย้ายพวกเขาไปยังGistสรุปสาระสำคัญเพื่อความสะดวกในการทดลองสคริปต์ใช้โหมด SQLCMD การทดสอบทำงานบน 2K5SP3, ดูอัลคอร์, 8GB

การทดสอบใบมีดครอบคลุมสามสถานการณ์:

  1. การจัดเตรียมดัชนีข้อมูลคลัสเตอร์ในลำดับเดียวกับเป้าหมาย
  2. การจัดเตรียมดัชนีแบบคลัสเตอร์ข้อมูลในลำดับย้อนกลับ
  3. จัดเตรียมข้อมูลแบบคลัสเตอร์โดย col2 ซึ่งมี INT แบบสุ่ม

เรียกใช้ครั้งแรกโดยแทรก 25 แถว

วิ่งครั้งที่ 1 25 แถว

แผนการดำเนินการทั้งสามแผนนั้นเหมือนกันไม่มีการเรียงลำดับใด ๆ เกิดขึ้นในแผนและการสแกนดัชนีแบบคลัสเตอร์คือ "orders = false"

การเรียกใช้ครั้งที่สองแทรก 26 แถว

วิ่งครั้งที่ 2, 26 แถว

เวลานี้แผนแตกต่างกัน

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

ดังนั้นจึงมีจุดเปลี่ยนที่ผู้เพิ่มประสิทธิภาพเห็นว่าจำเป็นต้องจัดเรียง ดังที่ @MartinSmith แสดงขึ้นสิ่งนี้ดูเหมือนจะเป็นไปตามแถวโดยประมาณที่จะแทรก บนอุปกรณ์ทดสอบของฉัน 25 ไม่ต้องการการเรียงลำดับ, 26 ทำ (2K5SP3, ดูอัลคอร์, 8GB)

สคริปต์ SQLCMD มีตัวแปรที่อนุญาตขนาดของแถวในตารางที่จะเปลี่ยนแปลง (เปลี่ยนความหนาแน่นของหน้า) และจำนวนแถวใน dbo.MyTable ก่อนที่จะแทรกเพิ่มเติม จากการทดสอบของฉันไม่มีผลต่อจุดเปลี่ยน

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

แก้ไข: 2011-10-28 20:15

ทำการทดสอบซ้ำบนอุปกรณ์เดียวกัน แต่ใช้ 2K8R2 เวลานี้จุดเปลี่ยนคือ 251 แถว อีกครั้งการเปลี่ยนแปลงความหนาแน่นของหน้าและการนับแถวที่มีอยู่จะไม่มีผลใด ๆ


8

ORDER BYประโยคในSELECTงบซ้ำซ้อน

มันซ้ำซ้อนเพราะแถวที่จะถูกแทรกหากจำเป็นต้องเรียงลำดับจะถูกจัดเรียงอยู่ดี

ให้เราสร้างกรณีทดสอบ

CREATE TABLE #Test (
    id INTEGER NOT NULL
);

CREATE UNIQUE CLUSTERED INDEX CL_Test_ID ON #Test (id);

CREATE TABLE #Sequence (
    number INTEGER NOT NULL
);

INSERT INTO #Sequence
SELECT number FROM master..spt_values WHERE name IS NULL;

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

SET STATISTICS PROFILE ON;
GO

ทีนี้ลองINSERTแถว 2K ลงในตารางโดยไม่มีORDER BYประโยค

INSERT INTO #Test
SELECT number
  FROM #Sequence

แผนการดำเนินการตามจริงสำหรับเคียวรีนี้มีดังต่อไปนี้

INSERT INTO #Test  SELECT number    FROM #Sequence
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

อย่างที่คุณเห็นมีตัวดำเนินการเรียงก่อนที่จะเกิด INSERT จริง

ทีนี้มาล้างตารางและINSERTแถว 2k ลงในตารางด้วยORDER BYประโยค

TRUNCATE TABLE #Test;
GO

INSERT INTO #Test
SELECT number
  FROM #Sequence
 ORDER BY number

แผนการดำเนินการตามจริงสำหรับเคียวรีนี้มีดังต่อไปนี้

INSERT INTO #Test  SELECT number    FROM #Sequence   ORDER BY number
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

โปรดทราบว่ามันเป็นแผนการดำเนินการเดียวกันกับที่ใช้สำหรับINSERTคำสั่งที่ไม่มีORDER BYข้อ

ตอนนี้การSortดำเนินการไม่จำเป็นเสมอไปตามที่ Mark Smith ได้แสดงไว้ในคำตอบอื่น (ถ้าจำนวนของแถวที่จะใส่ต่ำ) แต่ORDER BYประโยคยังคงซ้ำซ้อนในกรณีนั้นเพราะแม้จะมีความชัดเจนORDER BYไม่มีSortการดำเนินการจะถูกสร้างขึ้น โดยหน่วยประมวลผลแบบสอบถาม

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

Updated 2011/11/02: ในฐานะที่เป็นมาร์คสมิ ธ ได้แสดงให้เห็น , INSERTs ลงในตารางที่มีดัชนีคลัสเตอร์อาจไม่เคยต้องการที่จะเรียง - The ORDER BYประโยคยังเป็นซ้ำซ้อนในกรณีที่แม้ว่า

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