เหตุใดปุ่มลำดับ GUID จึงทำงานได้เร็วกว่าปุ่ม INT ตามลำดับในกรณีทดสอบของฉัน


39

หลังจากที่ถามนี้คำถามเปรียบเทียบลำดับและ guid ของที่ไม่ใช่ลำดับผมพยายามที่จะเปรียบเทียบประสิทธิภาพ INSERT เมื่อวันที่ 1) ตารางที่มีคีย์หลัก GUID เริ่มต้นตามลำดับด้วยnewsequentialid()และ 2) ตารางที่มีคีย์หลัก INT identity(1,1)เริ่มต้นตามลำดับด้วย ฉันคาดว่าหลังจะเร็วที่สุดเนื่องจากมีความกว้างน้อยกว่าจำนวนเต็มและมันก็ดูเหมือนจะง่ายกว่าในการสร้างจำนวนเต็มตามลำดับกว่า GUID ตามลำดับ แต่ด้วยความประหลาดใจของฉัน INSERTs บนตารางที่มีคีย์จำนวนเต็มช้ากว่าตาราง GUID ตามลำดับอย่างมีนัยสำคัญ

นี่แสดงการใช้เวลาเฉลี่ย (มิลลิวินาที) สำหรับการทดสอบการทำงาน:

NEWSEQUENTIALID()  1977
IDENTITY()         2223

มีใครอธิบายเรื่องนี้ได้บ้าง

มีการใช้การทดลองต่อไปนี้:

SET NOCOUNT ON

CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000


WHILE (@BatchCounter <= 20)
BEGIN 
BEGIN TRAN

DECLARE @LocalCounter INT = 0

    WHILE (@LocalCounter <= @NumRows)
    BEGIN
    INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
    SET @LocalCounter +=1
    END

SET @LocalCounter = 0

    WHILE (@LocalCounter <= @NumRows)
    BEGIN
    INSERT TestInt (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
    SET @LocalCounter +=1
    END

SET @BatchCounter +=1
COMMIT 
END

DBCC showcontig ('TestGuid2')  WITH tableresults
DBCC showcontig ('TestInt')  WITH tableresults

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWSEQUENTIALID()]
FROM TestGuid2
GROUP BY batchNumber

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [IDENTITY()]
FROM TestInt
GROUP BY batchNumber

DROP TABLE TestGuid2
DROP TABLE TestInt

อัปเดต: การ แก้ไขสคริปต์เพื่อดำเนินการแทรกตามตาราง TEMP เช่นในตัวอย่างโดย Phil Sandler, Mitch Wheat และ Martin ด้านล่างฉันพบว่าตัวตนนั้นเร็วกว่าที่ควรจะเป็น แต่นั่นไม่ใช่วิธีการทั่วไปของการแทรกแถวและฉันก็ยังไม่เข้าใจว่าทำไมการทดสอบผิดพลาดในตอนแรก: แม้ว่าฉันจะละเว้น GETDATE () จากตัวอย่างดั้งเดิมของฉัน IDENTITY () ก็ยังช้ากว่า ดังนั้นดูเหมือนว่าวิธีเดียวที่จะทำให้ IDENTITY () มีประสิทธิภาพเหนือกว่า NEWSEQUENTIALID () คือการเตรียมแถวที่จะแทรกในตารางชั่วคราวและทำการแทรกหลาย ๆ ครั้งเป็นชุดแทรกโดยใช้ตารางอุณหภูมินี้ โดยรวมแล้วฉันไม่คิดว่าเราจะพบคำอธิบายเกี่ยวกับปรากฏการณ์และตัวตน () ยังดูเหมือนว่าจะช้าลงสำหรับการใช้งานจริงมากที่สุด มีใครอธิบายเรื่องนี้ได้บ้าง


4
ความคิดเท่านั้น: เป็นไปได้ไหมว่าการสร้าง GUID ใหม่สามารถทำได้โดยไม่ต้องเกี่ยวข้องกับตารางเลยในขณะที่การรับค่าข้อมูลประจำตัวที่มีอยู่ถัดไปจะเป็นการแนะนำการล็อคแบบชั่วคราวเพื่อให้แน่ใจว่าสองเธรด / การเชื่อมต่อ ฉันแค่คาดเดาจริงๆ คำถามที่น่าสนใจ!
คนที่โกรธ

4
ใครบอกว่าพวกเขาทำ มีหลักฐานมากมายที่พวกเขาไม่เห็น - พื้นที่ดิสก์ของ Kimberly Tripp ราคาถูก - นั่นไม่ใช่ประเด็น! บล็อกโพสต์ - เธอทำการตรวจทานอย่างกว้างขวางและ GUID จะหลุดออกไปอย่างชัดเจนเสมอINT IDENTITY
marc_s

2
การทดลองข้างต้นแสดงให้เห็นถึงสิ่งที่ตรงกันข้ามและผลลัพธ์นั้นสามารถทำซ้ำได้
someName

2
การใช้IDENTITYไม่จำเป็นต้องล็อคตาราง แนวคิดฉันเห็นคุณอาจคาดหวังว่ามันจะใช้ MAX (id) + 1 แต่ในความเป็นจริงแล้วค่าถัดไปจะถูกเก็บไว้ จริง ๆ แล้วควรจะเร็วกว่าการค้นหา GUID ถัดไป

4
นอกจากนี้สมมุติว่าคอลัมน์ตัวเติมสำหรับตาราง TestGuid2 ควรเป็น CHAR (88) เพื่อทำให้แถวมีขนาดเท่ากัน
Mitch Wheat

คำตอบ:


19

ฉันแก้ไขรหัสของ @Phil Sandler เพื่อลบเอฟเฟกต์ของการโทร GETDATE () (อาจมีเอฟเฟกต์ฮาร์ดแวร์ / การขัดจังหวะที่เกี่ยวข้อง ??) และทำให้แถวยาวเท่ากัน

[มีหลายบทความตั้งแต่ SQL Server 2000 เกี่ยวกับปัญหาเรื่องเวลาและตัวจับเวลาความละเอียดสูงดังนั้นฉันจึงต้องการลดผลกระทบนั้น]

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

       Identity(s)  Guid(s)
       ---------    -----
       2.876        4.060    
       2.570        4.116    
       2.513        3.786   
       2.517        4.173    
       2.410        3.610    
       2.566        3.726
       2.376        3.740
       2.333        3.833
       2.416        3.700
       2.413        3.603
       2.910        4.126
       2.403        3.973
       2.423        3.653
    -----------------------
Avg    2.650        3.857
StdDev 0.227        0.204

รหัสที่ใช้:

SET NOCOUNT ON

CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(88))

CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

DECLARE @Numrows INT = 1000000

CREATE TABLE #temp (Id int NOT NULL Identity(1,1) PRIMARY KEY, rowNum int, adate datetime)

DECLARE @LocalCounter INT = 0

--put rows into temp table
WHILE (@LocalCounter < @NumRows)
BEGIN
    INSERT INTO #temp(rowNum, adate) VALUES (@LocalCounter, GETDATE())
    SET @LocalCounter += 1
END

--Do inserts using GUIDs
DECLARE @GUIDTimeStart DateTime = GETDATE()
INSERT INTO TestGuid2 (SomeDate, batchNumber) 
SELECT adate, rowNum FROM #temp
DECLARE @GUIDTimeEnd  DateTime = GETDATE()

--Do inserts using IDENTITY
DECLARE @IdTimeStart DateTime = GETDATE()
INSERT INTO TestInt (SomeDate, batchNumber) 
SELECT adate, rowNum FROM #temp
DECLARE @IdTimeEnd DateTime = GETDATE()

SELECT DATEDIFF(ms, @IdTimeStart, @IdTimeEnd) AS IdTime, DATEDIFF(ms, @GUIDTimeStart, @GUIDTimeEnd) AS GuidTime

DROP TABLE TestGuid2
DROP TABLE TestInt
DROP TABLE #temp
GO

หลังจากอ่านการสอบสวนของ @ Martin ฉันก็กลับไปทำงานกับ TOP ที่แนะนำ (@num) ในทั้งสองกรณีเช่น

...
--Do inserts using GUIDs
DECLARE @num INT = 2147483647; 
DECLARE @GUIDTimeStart DATETIME = GETDATE(); 
INSERT INTO TestGuid2 (SomeDate, batchNumber) 
SELECT TOP(@num) adate, rowNum FROM #temp; 
DECLARE @GUIDTimeEnd DATETIME = GETDATE();

--Do inserts using IDENTITY
DECLARE @IdTimeStart DateTime = GETDATE()
INSERT INTO TestInt (SomeDate, batchNumber) 
SELECT TOP(@num) adate, rowNum FROM #temp;
DECLARE @IdTimeEnd DateTime = GETDATE()
...

และนี่คือผลลัพธ์เวลา:

       Identity(s)  Guid(s)
       ---------    -----
       2.436        2.656
       2.940        2.716
       2.506        2.633
       2.380        2.643
       2.476        2.656
       2.846        2.670
       2.940        2.913
       2.453        2.653
       2.446        2.616
       2.986        2.683
       2.406        2.640
       2.460        2.650
       2.416        2.720

    -----------------------
Avg    2.426        2.688
StdDev 0.010        0.032

ฉันไม่สามารถรับแผนปฏิบัติการจริงได้เนื่องจากแบบสอบถามไม่ส่งคืน! ดูเหมือนว่าข้อผิดพลาดน่าจะเป็น (เรียกใช้ Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64))


7
แสดงองค์ประกอบสำคัญของการเปรียบเทียบที่ดี: ตรวจสอบให้แน่ใจว่าคุณวัดได้ทีละรายการเท่านั้น
Aaronaught

คุณวางแผนที่จะมาที่นี่? มีSORTโอเปอเรเตอร์สำหรับ GUID หรือไม่
Martin Smith

@ มาร์ติน: สวัสดีฉันไม่ได้ตรวจสอบแผน (ทำบางสิ่งในครั้งเดียว :)) ฉันจะดูทีหลัง ...
มิทช์ข้าวสาลี

@Mitch - ข้อเสนอแนะเกี่ยวกับเรื่องนี้? ฉันค่อนข้างจะสงสัยว่าสิ่งสำคัญที่คุณวัดที่นี่คือเวลาที่ใช้ในการจัดเรียง guids สำหรับเม็ดมีดขนาดใหญ่ซึ่งในขณะที่น่าสนใจไม่ได้ตอบคำถามดั้งเดิมของ OP ซึ่งเกี่ยวกับการให้คำอธิบายว่าทำไม แทรกแถวในการทดสอบของ OP
Martin Smith

2
@ Mitch - แม้ว่ายิ่งฉันคิดเกี่ยวกับมันมากเท่าไหร่ฉันก็ยิ่งเข้าใจน้อยลงว่าทำไมทุกคนถึงต้องการใช้NEWSEQUENTIALIDต่อไป มันจะทำให้ดัชนีลึกใช้ 20% หน้าข้อมูลในกรณี OP identityและมีการประกันเท่านั้นที่จะเพิ่มมากขึ้นเรื่อยจนกว่าเครื่องจะรีบูตเพื่อให้มีจำนวนมากของข้อเสียมากกว่า ดูเหมือนว่าในกรณีนี้ Query Plan จะเพิ่มสิ่งที่ไม่จำเป็นออกไปอีก!
Martin Smith

19

ในฐานข้อมูลใหม่ในรูปแบบการกู้คืนง่าย ๆ ที่มีไฟล์ข้อมูลขนาด 1GB และไฟล์บันทึกที่ 3GB (เครื่องแล็ปท็อปทั้งไฟล์ในไดรฟ์เดียวกัน) และช่วงเวลาการกู้คืนที่กำหนดไว้ที่ 100 นาที (เพื่อหลีกเลี่ยงจุดตรวจผลบิดเบือน) insertsผลลัพธ์ที่คล้ายกับคุณมีแถวเดียว

ฉันทดสอบสามกรณี: สำหรับแต่ละกรณีฉันได้ 20 กระบวนการของการแทรก 100,000 แถวเป็นรายบุคคลในตารางต่อไปนี้ สคริปต์เต็มสามารถพบได้ในประวัติการแก้ไขของคำตอบนี้

CREATE TABLE TestGuid
  (
     Id          UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
     SomeDate    DATETIME, batchNumber BIGINT, FILLER CHAR(100)
  )

CREATE TABLE TestId
  (
     Id          Int NOT NULL identity(1, 1) PRIMARY KEY,
     SomeDate    DATETIME, batchNumber BIGINT, FILLER CHAR(100)
  )

CREATE TABLE TestInt
  (
     Id          Int NOT NULL PRIMARY KEY,
     SomeDate    DATETIME, batchNumber BIGINT, FILLER  CHAR(100)
  )  

สำหรับตารางที่สามการทดสอบแทรกแถวด้วยIdค่าที่เพิ่มขึ้นแต่นี่เป็นการคำนวณด้วยตนเองโดยการเพิ่มค่าของตัวแปรในลูป

การเฉลี่ยเวลาที่ใช้ใน 20 กระบวนการให้ผลดังนี้

NEWSEQUENTIALID() IDENTITY()  INT
----------------- ----------- -----------
1999              2633        1878

ข้อสรุป

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

เมื่อฉันใส่รหัสแทรกที่อธิบายข้างต้นลงในขั้นตอนการจัดเก็บและตรวจสอบsys.dm_exec_procedure_statsมันจะให้ผลลัพธ์ดังต่อไปนี้

proc_name      execution_count      total_worker_time    last_worker_time     min_worker_time      max_worker_time      total_elapsed_time   last_elapsed_time    min_elapsed_time     max_elapsed_time     total_physical_reads last_physical_reads  min_physical_reads   max_physical_reads   total_logical_writes last_logical_writes  min_logical_writes   max_logical_writes   total_logical_reads  last_logical_reads   min_logical_reads    max_logical_reads
-------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- --------------------
IdentityInsert 20                   45060360             2231067              2094063              2645079              45119362             2234067              2094063              2660080              0                    0                    0                    0                    32505                1626                 1621                 1626                 6268917              315377               276833               315381
GuidInsert     20                   34829052             1742052              1696051              1833055              34900053             1744052              1698051              1838055              0                    0                    0                    0                    35408                1771                 1768                 1772                 6316837              316766               298386               316774

ดังนั้นในผลลัพธ์เหล่านั้นtotal_worker_timeจะสูงขึ้นประมาณ 30% สิ่งนี้แสดงถึง

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

ดังนั้นมันจึงดูเหมือนว่ารหัสที่สร้างIDENTITYค่าเป็น CPU ที่เข้มข้นมากกว่าสิ่งที่สร้างขึ้นNEWSEQUENTIALID()(ความแตกต่างระหว่าง 2 ตัวเลขคือ 10231308 ซึ่งค่าเฉลี่ยอยู่ที่ประมาณ 5 pers ต่อการแทรก) และสำหรับนิยามตารางนี้ต้นทุน CPU คงที่นี้ มีค่าสูงพอที่จะมีค่าเกินกว่าการอ่านและการเขียนเชิงตรรกะเพิ่มเติมเนื่องจากความกว้างของคีย์มากกว่า (หมายเหตุ: Itzik Ben Gan ทำการทดสอบที่คล้ายกันที่นี่และพบว่ามีโทษ 2 ต่อการแทรก)

เหตุใดจึงเป็นIDENTITYCPU เข้มข้นมากขึ้นกว่าUuidCreateSequential?

ผมเชื่อว่านี่คือการอธิบายในบทความนี้ สำหรับทุกidentityค่าที่สิบที่สร้างขึ้น SQL Server จะต้องเขียนการเปลี่ยนแปลงไปยังตารางระบบบนดิสก์

สิ่งที่เกี่ยวกับการแทรก MultiRow?

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

NEWSEQUENTIALID() IDENTITY()
----------------- -----------
1016              1088

SELECT TOP (@NumRows)เหตุผลที่มันไม่ได้มีการลงโทษที่ชัดเจนในรหัสของฟิลและมิทช์ชุดแรกของผลการค้นหาเป็นเพราะมันจึงเกิดขึ้นว่ารหัสที่ผมเคยทำแถวหลายแทรกใช้ สิ่งนี้ทำให้เครื่องมือเพิ่มประสิทธิภาพไม่สามารถประมาณจำนวนแถวที่จะแทรกได้อย่างถูกต้อง

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

จัดเรียง GUID

ดำเนินการเรียงลำดับนี้ไม่จำเป็นจากข้อความอธิบายใน BOL

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

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


ไม่ว่ามันจะมีผลกระทบมากมาย แต่เพียงเพื่อผลประโยชน์ที่ชัดเจนของตัวเลขที่เดนนี่อ้างถึงค่าแคช 20 ค่าไม่ถูกต้อง - ควรเป็น 10
Aaron Bertrand

@AaronBertrand - ขอบคุณ บทความที่คุณเชื่อมโยงนั้นมีข้อมูลมากที่สุด
Martin Smith

8

ค่อนข้างง่าย: ด้วย GUID จะมีราคาถูกกว่าในการสร้างหมายเลขถัดไปในบรรทัดกว่าสำหรับ IDENTITY (ค่าปัจจุบันของ GUID ไม่จำเป็นต้องเก็บไว้ IDENTITY ต้องเป็น) สิ่งนี้เป็นจริงแม้สำหรับ NEWSEQUENTIALGUID

คุณสามารถทำให้การทดสอบมีความยุติธรรมมากขึ้นและใช้ SEQUENCER ที่มี CACHE ขนาดใหญ่ซึ่งราคาถูกกว่าตัวตน

แต่ดังที่ MR กล่าวว่ามีข้อดีที่สำคัญบางประการสำหรับ GUID ตามความเป็นจริงพวกเขาสามารถปรับขนาดได้มากกว่าคอลัมน์ IDENTITY (แต่ถ้าไม่เรียงตามลำดับ)

ดู: http://blog.kejser.org/2011/10/05/boosting-insert-speed-by-generating-scalable-keys/


ฉันคิดว่าคุณพลาดว่าพวกเขากำลังใช้ guids ต่อเนื่อง
Martin Smith

Martin: การโต้แย้งนั้นเป็นจริงสำหรับ GUID ที่ต่อเนื่องเช่นกัน จะต้องมีการจัดเก็บข้อมูลประจำตัว (เพื่อกลับสู่ค่าเดิมหลังจากรีสตาร์ท) GUID ตามลำดับไม่มีข้อ จำกัด นี้
โทมัส Kejser

2
ใช่รับรู้หลังจากความคิดเห็นของฉันคุณกำลังพูดถึงการจัดเก็บอย่างต่อเนื่องมากกว่าที่จะเก็บไว้ในหน่วยความจำ 2012 ใช้แคชIDENTITYเช่นกัน ดังนั้นการร้องเรียนที่นี่
Martin Smith

4

ฉันรู้สึกทึ่งกับคำถามประเภทนี้ ทำไมคุณต้องโพสต์ไว้ในคืนวันศุกร์ :)

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

ฉันไม่มั่นใจว่าเวอร์ชั่นของฉันจะพิสูจน์อะไรได้อย่างสมบูรณ์ แต่ตัวตนจะทำงานได้ดีกว่า GUID ในนั้น (3.2 วินาทีเทียบกับ 6.8 วินาทีบนพีซีที่บ้าน):

SET NOCOUNT ON

CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

DECLARE @Numrows INT = 1000000

CREATE TABLE #temp (Id int NOT NULL Identity(1,1) PRIMARY KEY, rowNum int)

DECLARE @LocalCounter INT = 0

--put rows into temp table
WHILE (@LocalCounter < @NumRows)
BEGIN
    INSERT INTO #temp(rowNum) VALUES (@LocalCounter)
    SET @LocalCounter += 1
END

--Do inserts using GUIDs
DECLARE @GUIDTimeStart DateTime = GETDATE()
INSERT INTO TestGuid2 (SomeDate, batchNumber) 
SELECT GETDATE(), rowNum FROM #temp
DECLARE @GUIDTimeEnd  DateTime = GETDATE()

--Do inserts using IDENTITY
DECLARE @IdTimeStart DateTime = GETDATE()
INSERT INTO TestInt (SomeDate, batchNumber) 
SELECT GETDATE(), rowNum FROM #temp
DECLARE @IdTimeEnd DateTime = GETDATE()

SELECT DATEDIFF(ms, @IdTimeStart, @IdTimeEnd) AS IdTime
SELECT DATEDIFF(ms, @GUIDTimeStart, @GUIDTimeEnd) AS GuidTime

DROP TABLE TestGuid2
DROP TABLE TestInt
DROP TABLE #temp

ปัจจัยอื่น ๆ ที่ไม่มีใครได้กล่าวถึงเป็นฐานข้อมูลรูปแบบการกู้คืนและแฟ้มบันทึกการเจริญเติบโต ...
มิทช์ข้าวสาลี

@ Mitch บนฐานข้อมูลใหม่ในรูปแบบการกู้คืนข้อมูลอย่างง่ายพร้อมข้อมูลและไฟล์บันทึกทั้งขนาดที่ต้องการฉันได้ผลลัพธ์ที่คล้ายกันกับ OP
Martin Smith

ฉันเพิ่งได้เวลา 2.560 วินาทีสำหรับ Identity และ 3.666 วินาทีสำหรับ Guid (ในรูปแบบการกู้คืนข้อมูลและไฟล์บันทึกที่มีขนาดเท่าที่จำเป็น)
Mitch Wheat

@Mitch - ในรหัสของ OP ด้วยทุกอย่างในการทำธุรกรรมเดียวกันหรือในรหัสของ Phil?
Martin Smith

ในรหัสโปสเตอร์นี้นั่นเป็นเหตุผลที่ฉันแสดงความคิดเห็นที่นี่ ฉันได้โพสต์รหัสที่ฉันใช้ ...
มิทช์ข้าวสาลี

3

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

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

การค้นพบของฉันโดยทั่วไปคล้ายกับของคุณ แต่ผมจะพูดถึงความแปรปรวนในการที่INSERTระหว่างความเร็วGUIDและIDENTITY(int) เล็กน้อยขนาดใหญ่ที่มีGUIDกว่าด้วยIDENTITY- อาจ +/- 10% ระหว่างวิ่ง กระบวนการที่ใช้IDENTITYแตกต่างกันน้อยกว่า 2 - 3% ในแต่ละครั้ง

นอกจากนี้เพื่อทราบว่ากล่องทดสอบของฉันมีพลังน้อยกว่าของคุณอย่างชัดเจนดังนั้นฉันจึงต้องใช้จำนวนแถวที่น้อยลง


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

1

ฉันจะอ้างอิงกลับไปที่ Conv อื่นใน stackoverflow สำหรับหัวข้อเดียวกันนี้ - https://stackoverflow.com/questions/170346/what-are-the-performance-improvement-of-sequential-guid-over-standard-guid

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

ประสบการณ์ส่วนตัวของฉันคือเมื่อคุณใช้งานฐานข้อมูลปริมาณการใช้ข้อมูลขนาดใหญ่จะใช้ guid ได้ดีกว่าเพราะจะทำให้สามารถปรับขนาดได้มากขึ้นสำหรับการรวมเข้ากับระบบอื่น ๆ นั่นเป็นไปเพื่อการจำลองแบบโดยเฉพาะและการ จำกัด int / bigint .... ไม่ใช่ว่าคุณจะหมด bigints แต่ในที่สุดคุณจะและรอบกลับ


1
คุณไม่ได้ใช้งาน BIGINTs เลย ... ดูสิ่งนี้: sqlmag.com/blog/it-possible-run-out-bigint-values
Thomas Kejser
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.