ทางออกที่ดีที่สุดในการแก้ไขการออกแบบฐานข้อมูลด้วย GUID เป็นคีย์หลัก


18

ฉันหลังจากการยืนยันแนวคิดนี้เพื่อแก้ไขฐานข้อมูลที่มีประสิทธิภาพไม่ดีหรือมีข้อเสนอแนะที่ดีกว่าถ้ามีใครมี เปิดรับข้อเสนอแนะที่ดีกว่าเสมอ

ฉันมีฐานข้อมูลขนาดใหญ่มาก (มากกว่า 20 ล้านบันทึกการเติบโตประมาณ 1/2 ล้านต่อวัน) ซึ่งใช้ GUID เป็น PK

การดูแลในส่วนของฉัน แต่ PK นั้นทำคลัสเตอร์บนเซิร์ฟเวอร์ SQL และทำให้เกิดปัญหาประสิทธิภาพการทำงาน

เหตุผลสำหรับ guid - ฐานข้อมูลนี้มีการซิงโครไนซ์บางส่วนกับฐานข้อมูลอื่น 150 ฐานดังนั้น PK จึงจำเป็นต้องไม่ซ้ำกัน การซิงโครไนซ์ไม่ได้รับการจัดการโดย SQL Server แต่มีกระบวนการแบบกำหนดเองที่สร้างขึ้นซึ่งเก็บข้อมูลให้ตรงกับความต้องการของระบบ - ทั้งหมดขึ้นอยู่กับ GUID นั้น

ฐานข้อมูลระยะไกล 150 ตัวแต่ละตัวไม่เก็บข้อมูลแบบเต็มตามที่เก็บไว้ในฐานข้อมูล SQL ส่วนกลาง พวกเขาจัดเก็บชุดย่อยของข้อมูลที่พวกเขาต้องการจริงและข้อมูลที่ต้องการนั้นไม่ซ้ำกัน (10 จาก 150 ฐานข้อมูลอาจมีบางระเบียนเดียวกันจากฐานข้อมูลไซต์อื่นเช่นพวกเขาแบ่งปัน) นอกจากนี้ - ข้อมูลถูกสร้างขึ้นจริงที่ไซต์ระยะไกล - ไม่ใช่ที่จุดศูนย์กลาง - ดังนั้นจึงจำเป็นต้องมี GUID

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

โชคดีที่เรายังไม่ได้อยู่ - ดังนั้นฉันสามารถเปลี่ยนแปลงและทำสิ่งต่าง ๆ แบบออฟไลน์ได้ถ้าจำเป็นซึ่งอย่างน้อยก็มีบางอย่าง

ประสิทธิภาพของฐานข้อมูลระยะไกลไม่ใช่ปัญหา - ชุดย่อยของข้อมูลมีขนาดค่อนข้างเล็กและโดยปกติฐานข้อมูลจะไม่มีขนาดใหญ่กว่า 1GB ข้อมูลจะถูกส่งกลับไปยังระบบหลักอย่างสม่ำเสมอและลบออกจาก BD ที่มีขนาดเล็กลงเมื่อไม่ต้องการใช้อีกต่อไป

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

ดังนั้น - ความคิดของฉันในการแก้ไขปัญหาด้านประสิทธิภาพคือการสร้างคอลัมน์ใหม่ - รหัสประจำตัว BIGINT ที่ไม่ได้ลงชื่อ (1,1) จากนั้นเปลี่ยน PK แบบกลุ่มของคอลัมน์ BIGINT ตาราง

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

ฐานข้อมูลระยะไกลขนาดเล็ก 150 ไม่จำเป็นต้องรู้เกี่ยวกับ PK ใหม่ในฐานข้อมูล SQL Server กลาง - มันจะใช้สำหรับการจัดระเบียบข้อมูลในฐานข้อมูลและหยุดประสิทธิภาพและการกระจายตัวที่ไม่ดี

มันจะทำงานและปรับปรุงประสิทธิภาพของฐานข้อมูล SQL กลางและป้องกันการแตกแฟรกเมนต์ดัชนีในอนาคต (ในระดับหนึ่ง) หรือไม่? หรือฉันพลาดบางสิ่งที่สำคัญมากที่นี่ซึ่งจะกระโดดขึ้นไปกัดฉันและทำให้เกิดความเศร้าโศกมากยิ่งขึ้น?


2
@mattytommo ฉันเห็นด้วย
Paul Fleming

2
คุณใช้การจัดเรียงดัชนีอย่างน้อยสัปดาห์ละครั้งหรือไม่
Andomar

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

2
@Borik ไม่ใช่ความคิดที่ดีขึ้นอยู่กับสิ่งที่เขามีและอัตราการเติบโตของเขาเขาจะหมดintใน 4255 วัน (11.5 ปี) ถ้าเขาทำอย่างนั้นเขาจะโทษคุณใน 11.5 ปีเท่านั้น)
mattytommo

1
มุมมองตรงกันข้าม: ทำไมคุณคิดว่าประเภทข้อมูล GUID เป็นปัญหา มันเป็นจำนวนเต็ม 128 บิต ทำไมคุณถึงคิดว่าการแทนที่ด้วยจำนวนเต็ม 64- บิต (bigint) หรือจำนวนเต็ม 32- บิต (int) จะสร้างความแตกต่างที่เห็นได้ชัดในความเร็ว? ฉันคิดว่าคุณควรเปลี่ยนคีย์การทำคลัสเตอร์เป็นอย่างอื่นเพื่อหลีกเลี่ยงการแยกหน้าทั้งหมดที่นำไปสู่การแยกส่วน แต่ฉันไม่คิดว่าคุณควรเปลี่ยนประเภทข้อมูลเว้นแต่คุณจะแน่ใจว่าประเภทข้อมูลเป็นปัญหา
Greenstone Walker

คำตอบ:


8

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

ปัญหาเกี่ยวกับการเปลี่ยนเป็น a BIGINTจะเป็นการเพิ่มเติมไปยังข้อมูลจากฐานข้อมูลอื่น ๆ และการรวมฐานข้อมูลของพวกเขาเข้ากับร้านค้าส่วนกลาง หากนี่ไม่ใช่การพิจารณาและจะไม่มีการพิจารณาใช่แล้วBIGINTจะช่วยแก้ปัญหาการปรับสมดุลดัชนีใหม่

เบื้องหลังหากคุณไม่ระบุดัชนีคลัสเตอร์ SQL Server จะทำสิ่งเดียวกันมาก: มันจะสร้างฟิลด์ ID แถว & แมปดัชนีอื่น ๆ ทั้งหมดลงในนั้น ด้วยการทำด้วยตัวคุณเองคุณกำลังแก้ไขมันเหมือนที่ SQL จะแก้มัน


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

ผลการปฏิบัติงานหากคุณไม่ระบุดัชนีคลัสเตอร์คือ SQL จะสร้างดัชนีหนึ่งหลังสำหรับคุณและแมปดัชนีอื่นทั้งหมดลงในดัชนีนั้น ในกรณีของคุณคุณจะได้รับการปรับปรุงประสิทธิภาพโดยให้ SQL ทำเช่นนั้นเพราะตอนนี้คุณสับข้อมูลทั้งหมดของคุณบนดิสก์อย่างต่อเนื่องเพื่อรักษาลำดับการเรียงเมื่อลำดับการเรียงไม่สำคัญ คุณจะต้องการพื้นที่เก็บข้อมูลเพิ่มขึ้น แต่จะเห็นการปรับปรุงที่กว้างขวางในการจัดเก็บและผลกระทบเล็กน้อย / ไม่มีผลกระทบต่อการดึงข้อมูล
David T. Macknet

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

+1 ฉันอยากจะแนะนำให้อยู่กับ GUID ด้วย ยากมากที่จะแทนที่พวกเขาในระบบกระจาย ดัชนีคลัสเตอร์ตารางขนาดใหญ่ของคุณควรปรากฏให้เห็นตามวิธีที่คุณค้นหาข้อมูล
Remus Rusanu

1
สวัสดีคน - แค่อัปเดต - ฉันทำการแก้ไขและทำให้ PK เป็นแบบไม่รวมกลุ่มบน GUID และ SQL Server ไม่ว่างที่จะแทรกระเบียน 2 ล้านรายการลงในฐานข้อมูล ในขณะเดียวกันข้อมูลที่ถูกแทรกเข้าไปนั้นฉันสามารถสืบค้นฐานข้อมูลเพื่อสอบถามและสอบถามว่าในบางครั้งก่อนที่การเปลี่ยนแปลงจะหมดเวลา 10 นาทีแล้วเสร็จในเวลา 1-2 วินาที ดังนั้นการทำให้ PK ไม่เป็นกลุ่มและไม่ต้องกังวลกับ BIGINT ดูเหมือนว่าจะทำงานได้ดี ขอบคุณมากสำหรับอินพุตและความช่วยเหลือของทุกคน
Roddles

1

นั่นเป็นคำสั่งที่สูง

ฉันขอแนะนำวิธีการชายกลาง

ฉันมีปัญหากับ System.Guid.NewGuid () กำลังสร้าง guids แบบสุ่ม (ฉันอนุญาตให้ไคลเอนต์สร้าง guid ของตนเองแทนที่จะใช้ฐานข้อมูลเพื่อสร้างลำดับ)

เมื่อฉันย้ายไปที่ UuidCreateSequential ทางฝั่งลูกค้าการแสดงของฉันดีขึ้นมากโดยเฉพาะ INSERTs

นี่คือรหัสลูกค้าของ DotNet ฉันแน่ใจว่าฉันจำนำได้จากที่ไหนสักแห่ง:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;


namespace MyCompany.MyTechnology
{
  public static class Guid
  {


    [DllImport("rpcrt4.dll", SetLastError = true)]
    static extern int UuidCreateSequential(out System.Guid guid);


    public static System.Guid NewGuid()
    {
      return CreateSequentialUUID();
    }


    public static System.Guid CreateSequentialUUID()
    {
      const int RPC_S_OK = 0;
      System.Guid g;
      int hr = UuidCreateSequential(out g);
      if (hr != RPC_S_OK)
        throw new ApplicationException("UuidCreateSequential failed: " + hr);
      return g;
    }


  }
}














    /*

Original Reference for Code:
http://www.pinvoke.net/default.aspx/rpcrt4/UuidCreateSequential.html


*/

/*



Text From URL above:

UuidCreateSequential (rpcrt4)

Type a page name and press Enter. You'll jump to the page if it exists, or you can create it if it doesn't.
To create a page in a module other than rpcrt4, prefix the name with the module name and a period.
. Summary
Creates a new UUID 
C# Signature:
[DllImport("rpcrt4.dll", SetLastError=true)]
static extern int UuidCreateSequential(out Guid guid);


VB Signature:
Declare Function UuidCreateSequential Lib "rpcrt4.dll" (ByRef id As Guid) As Integer


User-Defined Types:
None.

Notes:
Microsoft changed the UuidCreate function so it no longer uses the machine's MAC address as part of the UUID. Since CoCreateGuid calls UuidCreate to get its GUID, its output also changed. If you still like the GUIDs to be generated in sequential order (helpful for keeping a related group of GUIDs together in the system registry), you can use the UuidCreateSequential function.

CoCreateGuid generates random-looking GUIDs like these:

92E60A8A-2A99-4F53-9A71-AC69BD7E4D75
BB88FD63-DAC2-4B15-8ADF-1D502E64B92F
28F8800C-C804-4F0F-B6F1-24BFC4D4EE80
EBD133A6-6CF3-4ADA-B723-A8177B70D268
B10A35C0-F012-4EC1-9D24-3CC91D2B7122



UuidCreateSequential generates sequential GUIDs like these:

19F287B4-8830-11D9-8BFC-000CF1ADC5B7
19F287B5-8830-11D9-8BFC-000CF1ADC5B7
19F287B6-8830-11D9-8BFC-000CF1ADC5B7
19F287B7-8830-11D9-8BFC-000CF1ADC5B7
19F287B8-8830-11D9-8BFC-000CF1ADC5B7



Here is a summary of the differences in the output of UuidCreateSequential:

The last six bytes reveal your MAC address 
Several GUIDs generated in a row are sequential 
Tips & Tricks:
Please add some!

Sample Code in C#:
static Guid UuidCreateSequential()
{
   const int RPC_S_OK = 0;
   Guid g;
   int hr = UuidCreateSequential(out g);
   if (hr != RPC_S_OK)
     throw new ApplicationException
       ("UuidCreateSequential failed: " + hr);
   return g;
}



Sample Code in VB:
Sub Main()
   Dim myId As Guid
   Dim code As Integer
   code = UuidCreateSequential(myId)
   If code <> 0 Then
     Console.WriteLine("UuidCreateSequential failed: {0}", code)
   Else
     Console.WriteLine(myId)
   End If
End Sub




*/

ALTERATE IDEA:

หากฐานข้อมูลหลักและฐานข้อมูลระยะไกลของคุณเป็น "เชื่อมโยง" (เหมือนใน sp_linkserver) ...... คุณสามารถใช้ฐานข้อมูลหลักเป็น "ตัวสร้าง uuid" ได้

คุณไม่ต้องการที่จะได้รับ "หนึ่งโดยหนึ่ง" ของ uuid นั่นคือความมีเสน่ห์มากเกินไป

แต่คุณสามารถคว้าชุด uuid ได้

ด้านล่างเป็นรหัสบางส่วน:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
 OBJECT_ID(N'[dbo].[uspNewSequentialUUIDCreateRange]') AND type in (N'P',
 N'PC'))

 DROP PROCEDURE [dbo].[uspNewSequentialUUIDCreateRange]

 GO



 CREATE PROCEDURE [dbo].[uspNewSequentialUUIDCreateRange] (

 @newUUIDCount int --return

 )

 AS

 SET NOCOUNT ON

 declare @t table ( dummyid int , entryid int identity(1,1) , uuid
 uniqueidentifier default newsequentialid() )

 insert into @t ( dummyid ) select top (@newUUIDCount) 0 from dbo.sysobjects
 so with (nolock)

 select entryid , uuid from @t

 SET NOCOUNT OFF

 GO

/ *

--START TEST

 set nocount ON

 Create Table #HolderTable (entryid int , uuid uniqueidentifier )

 declare @NewUUIDCount int

 select @NewUUIDCount = 20

 INSERT INTO #HolderTable EXEC dbo.uspNewSequentialUUIDCreateRange
 @NewUUIDCount

 select * from #HolderTable

 DROP Table #HolderTable

 --END TEST CODE

* /


สิ่งที่น่าสนใจ - และวิธีการที่ฉันไม่ได้พิจารณา - ฉันจะตรวจสอบสิ่งนี้อย่างใกล้ชิดยิ่งขึ้นเนื่องจากนี่ดูดีและใช้งานโครงการทดสอบบางอย่าง หากเรามีฐานข้อมูล 150 ฐานที่สร้าง guid ที่ต่อเนื่องกันซึ่งรายงานกลับไปยังฐานข้อมูลกลางสิ่งนี้จะไม่ทำให้เกิดการแตกแฟรกเมนต์เนื่องจาก guids จะยังคงสุ่มเมื่อแทรกลงในฐานข้อมูลกลาง นอกเสียจากว่าคุณหมายถึงปล่อย PK แบบคลัสเตอร์และมี PK แบบไม่รวมกลุ่ม
Roddles

ฐานข้อมูล 150 "รีโมต" แทรกครั้งละหนึ่งฐานข้อมูลหรือไม่? หรือพวกเขากำลังย้ายข้อมูลในชุดจำนวนมากในเวลากลางคืนหรืออะไร? ดังนั้นคุณจะต้องอยู่ระหว่างหินและสถานที่ที่ยากลำบาก ในที่สุดการใช้ bigint จะหมดลงในห้อง (บางที) และคุณยังต้องได้รับค่าที่ไม่ซ้ำใครในฐานข้อมูลจำนวนมาก ดังนั้นนี่คือความคิดที่รุนแรงของฉัน 150 ฐานข้อมูลระยะไกลสามารถรับ UUID จากบริการส่วนกลางได้หรือไม่ นั่นเป็นความคิดหนึ่ง ฐานข้อมูลระยะไกล 150 รายการ "เชื่อมโยง" (เหมือนใน sp_addlinkedserver) ไปยังฐานข้อมูลหลักหรือไม่ จากนั้นฉันก็มี UDF ที่อาจถูกพิจารณา ให้ฉันดูว่าฉันสามารถหาได้
granadaCoder

นี่คือบทความที่พูดถึงเกี่ยวกับ
ซีเควนเชียล

0

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


-1

ถ้า GUID ถูกเก็บไว้อย่างถูกต้องเนื่องจากตัวระบุที่ไม่ควรมีปัญหา performace ใด ๆ ... และถ้าคุณสามารถใช้ GUID ลำดับที่ดียิ่งขึ้น ...

ยัง @mattytommo มีจุดที่ดีประมาณ 11.5 ปีเมื่อใช้ INT ...


ใช่ - แต่ guid ถูกสร้างขึ้นที่ฐานข้อมูลระยะไกล 150 ไม่ใช่ฐานข้อมูล SQL Server - ดังนั้นฉันไม่สามารถใช้ sequentialguid ได้ - แต่ขอบคุณสำหรับการตอบสนอง
Roddles

ในกรณีที่แผนของคุณในความคิดของฉันเป็นสิ่งที่ดีฉันได้ทำสิ่งที่คล้ายกันกับหนึ่งในฐานข้อมูลที่ฉันจัดการฉันได้สร้าง INT DENTITY (1,1) และตั้งค่าเป็น Clustered PK รวมถึงตัวระบุที่อ่านได้อย่างมีมนุษยธรรมสำหรับข้อมูล ดึงขึ้นและฉันเก็บ GUID (ดัชนี) เป็นตัวติดตามเพื่อให้สามารถติดตามตำแหน่งที่มา แต่แรงจูงใจของฉันได้มากขึ้นจากการประหยัดพื้นที่ ...
Borik

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