Solusi terbaik untuk memperbaiki desain database dengan GUID sebagai kunci utama

18

Saya setelah beberapa konfirmasi dari ide ini untuk memperbaiki database berkinerja buruk atau saran yang lebih baik jika ada yang memilikinya. Selalu terbuka untuk saran yang lebih baik.

Saya memiliki basis data yang sangat besar (20+ juta catatan tumbuh sekitar 1/2 juta per hari) yang menggunakan GUID sebagai PK.

Pengawasan pada bagian saya tetapi PK berkerumun di SQL server dan menyebabkan masalah kinerja.

Alasan untuk panduan - database ini sebagian disinkronkan dengan 150 database lain sehingga PK harus unik. Sinkronisasi tidak dikelola oleh SQL Server, melainkan ada proses kustom yang dibangun yang membuat data tetap sinkron untuk persyaratan sistem - semua didasarkan pada GUID itu.

Masing-masing dari 150 basis data jauh tidak menyimpan data lengkap seperti yang disimpan di Database SQL pusat. mereka hanya menyimpan sebagian dari data yang sebenarnya mereka butuhkan, dan data yang dibutuhkan tidak unik bagi mereka (10 dari 150 basis data mungkin memiliki beberapa catatan yang sama dari basis data situs lain misalnya - mereka bagikan). Juga - data sebenarnya dihasilkan di lokasi terpencil - bukan di titik pusat - maka kebutuhan untuk GUID.

Basis data pusat digunakan tidak hanya untuk menjaga semuanya tetap sinkron, tetapi permintaan dari 3000+ pengguna akan dieksekusi terhadap database terfragmentasi yang sangat besar. Ini sudah merupakan masalah besar dalam pengujian awal.

Untungnya kita belum tayang - jadi saya bisa membuat perubahan dan membuat offline jika diperlukan yang setidaknya adalah sesuatu.

Kinerja basis data jauh bukanlah masalah - himpunan bagian data cukup kecil dan database biasanya tidak pernah mencapai di atas 1GB secara total. Catatan dimasukkan kembali ke sistem utama secara teratur dan dihapus dari BD yang lebih kecil ketika tidak lagi diperlukan.

Kinerja pusat DB yang merupakan penjaga semua catatan menyedihkan - karena GUID berkerumun sebagai kunci utama untuk banyak catatan. Fragmentasi indeks tidak aktif.

Jadi - pemikiran saya untuk memperbaiki masalah kinerja adalah membuat kolom baru - IDENTITAS BIGINT yang tidak ditandatangani (1,1) dan kemudian mengubah PK yang dikelompokkan dari tabel kolom BIGINT.

Saya akan membuat indeks Unik Non Clustered pada bidang GUID yang merupakan kunci utama.

Remote 150 database yang lebih kecil tidak perlu tahu tentang PK baru pada database SQL Server Pusat - ini murni akan digunakan untuk mengatur data dalam database dan menghentikan kinerja buruk dan fragmentasi.

Apakah ini bekerja dan meningkatkan kinerja database SQL pusat dan mencegah neraka masa depan indeks fragmentasi (ke tingkat tertentu)? atau apakah saya melewatkan sesuatu yang sangat penting di sini yang akan melompat dan menggigit saya dan menyebabkan lebih banyak kesedihan?

Roddles
sumber
2
@mattytommo saya setuju.
Paul Fleming
2
Apakah Anda menjalankan defragmentasi indeks setidaknya sekali seminggu?
Andomar
1
Apakah Anda memiliki sesuatu yang bermakna untuk dikelompokkan? Yaitu, permintaan apa yang harus cepat? Jelas ini bukan pemindaian jarak jauh pada panduan, jadi alih-alih hanya memilih peningkatan otomatis, pertimbangkan jika ada beberapa pengelompokan optimal waktu-kueri yang dapat Anda pilih. Jika tidak, silakan gunakan bigint
2
@Borik Bukan ide bagus, berdasarkan apa yang dia miliki dan tingkat pertumbuhannya, dia akan inthabis dalam 4255 hari (11,5 tahun). Jika dia melakukan itu, dia hanya akan menyalahkanmu dalam 11,5 tahun;)
mattytommo
1
Pandangan sebaliknya: Menurut Anda mengapa tipe data GUID merupakan masalah? Ini adalah integer 128-bit. Menurut Anda mengapa menggantinya dengan integer 64-bit (bigint) atau integer 32-bit akan membuat perbedaan kecepatan yang nyata? Saya pikir Anda harus benar-benar mengubah kunci pengelompokan ke sesuatu yang lain, untuk menghindari semua pemisahan halaman yang mengarah ke fragmentasi, tetapi saya tidak berpikir Anda harus mengubah datatype kecuali Anda sangat yakin bahwa datatype adalah masalahnya.
Greenstone Walker

Jawaban:

8

Anda tentu TIDAK perlu mengelompokkan pada GUID. Jika Anda memiliki sesuatu yang akan memungkinkan Anda untuk mengidentifikasi secara unik catatan selain dari GUID itu, saya sarankan Anda melihat membangun indeks unik pada bidang lain & membuat indeks itu mengelompok. Jika tidak, Anda bebas mengelompokkan pada bidang lain, bahkan menggunakan indeks nonunique. Pendekatannya adalah dengan mengelompokkan namun terbaik memfasilitasi pemisahan data Anda dan permintaan - jadi, jika Anda memiliki bidang "wilayah", atau sesuatu, yang mungkin menjadi kandidat untuk skema pengelompokan Anda.

Masalah dengan mengubah ke BIGINTakan penambahan data dari database lain & mengintegrasikan database mereka ke dalam toko pusat. Jika ini bukan pertimbangan - dan tidak akan pernah menjadi pertimbangan - maka, ya, BIGINTakan menyelesaikan masalah penyeimbangan ulang indeks dengan baik.

Di belakang layar, jika Anda tidak menentukan indeks berkerumun, SQL Server melakukan hal yang sama: menciptakan bidang ID baris & memetakan semua indeks lainnya ke dalamnya. Jadi, dengan melakukannya sendiri, Anda menyelesaikannya seperti SQL akan menyelesaikannya.

David T. Macknet
sumber
Satu-satunya bidang yang benar-benar unik dalam tabel adalah GUD - kolom lainnya tidak unik dan ada kombinasi kolom bersama yang mungkin unik untuk memulai - tetapi seiring waktu ada sedikit kemungkinan bahwa mereka akan menghasilkan catatan duplikat. Sangat jauh tetapi dimungkinkan mengingat sifat data. Saya telah membaca bahwa semua indeks yang tidak berkerumun mengacu pada indeks berkerumun untuk meningkatkan kinerja pencarian, dll. Tidak akan memiliki PK berkerumun karena GUID menyebabkan dampak kinerja? Saya menyadari ruang dan sementara kekhawatiran - kinerja sangat penting.
Roddles
Hit performa, jika Anda tidak menentukan indeks berkerumun, adalah bahwa SQL akan membuat satu di belakang layar untuk Anda dan memetakan semua indeks lain ke dalam yang itu. Jadi, dalam kasus Anda, Anda akan mendapatkan peningkatan kinerja dengan membiarkan SQL melakukan itu, karena saat ini Anda terus-menerus mengocok semua data Anda di dalam disk untuk mempertahankan urutan pengurutan ketika urutan pengurutan tidak penting. Anda akan membutuhkan lebih banyak ruang penyimpanan, tetapi akan melihat peningkatan besar dalam penyimpanan dan minimal / tidak berdampak pada pengambilan.
David T. Macknet
JADI pertanyaan yang saya kira adalah jika saya tidak melakukan BIGINT Clustered PK, dan hanya mengubah PK menjadi GUID Non Clustered, apa implikasi kinerjanya? Ada indeks non clustered lain di atas meja yang akan sering dicari. Apakah ini berdampak pada kinerja pencarian tersebut?
Roddles
+1 Saya juga menyarankan untuk tetap dengan GUID. Sangat sulit untuk menggantinya dalam sistem terdistribusi. Indeks berkerumun tabel besar Anda harus jelas berdasarkan pada bagaimana Anda meminta data.
Remus Rusanu
1
Hai Teman-teman - Hanya pembaruan - saya membuat modifikasi dan membuat PK menjadi Non Clustered pada GUID dan SQL Server sibuk memasukkan 2+ juta catatan ke dalam database. Pada saat yang sama, data dimasukkan, saya dapat meminta informasi dari database dan pertanyaan yang pada waktu sebelum perubahan habis pada 10 menit, selesai dalam hitungan 1-2 detik. Jadi - membuat PK tidak terkelompok dan tidak mengkhawatirkan BIGINT tampaknya berhasil dengan baik. Terima kasih banyak atas masukan dan bantuan semua orang.
Roddles
1

Itu perintah yang sulit.

Izinkan saya menyarankan pendekatan perantara.

Saya mengalami masalah dengan System.Guid.NewGuid () menghasilkan panduan acak. (Saya mengizinkan klien untuk membuat panduan mereka sendiri, daripada mengandalkan database untuk membuat sequentialid).

Setelah saya pindah ke UuidCreateSequential di sisi klien, kinerja saya menjadi JAUH lebih baik, terutama pada INSERT.

Berikut ini adalah kode klien DotNet voodoo. Saya yakin saya menggadaikan dari suatu tempat:

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




*/

ALTERNATE IDEA:

Jika db utama dan remote db Anda "ditautkan" (seperti pada, sp_linkserver) ...... maka Anda bisa menggunakan db utama sebagai "generator uuid".

Anda tidak ingin mendapatkan uuid's "satu per satu", itu terlalu banyak mengobrol.

Tapi Anda bisa mengambil satu set uuid.

Berikut ini beberapa kode:

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

* /

granadaCoder
sumber
Menarik - dan pendekatan yang tidak saya pertimbangkan - saya akan memeriksanya lebih dekat karena ini terlihat bagus dan menjalankan beberapa proyek uji. Jika kami memiliki 150 basis data yang menghasilkan pengurutan berurutan yang dilaporkan kembali ke basis data pusat, apakah ini tidak akan menyebabkan fragmentasi karena pengenal tersebut masih cukup acak ketika dimasukkan ke dalam basis data pusat. Kecuali tentu saja maksud Anda menjatuhkan PK berkerumun dan memiliki PK non berkerumun?
Roddles
Apakah 150 basis data "jarak jauh" memasukkan satu per satu? Atau apakah mereka memindahkan data dalam jumlah besar di malam hari atau apa? Jadi Anda berada di antara batu dan tempat yang sulit. Menggunakan bigint akhirnya akan kehabisan ruang (mungkin) dan Anda masih harus mendapatkan nilai unik di banyak db. Jadi, inilah ide radikal saya. Bisakah 150 basis data jauh mendapatkan UUID mereka dari layanan pusat? Itu satu ide. Apakah 150 basis data jauh "ditautkan" (seperti pada sp_addlinkedserver) ke basis data utama? Lalu saya punya UDF yang mungkin bisa dipertimbangkan. Biarkan saya melihat apakah saya dapat menemukannya.
granadaCoder
Berikut adalah sebuah artikel yang berbicara tentang ini sequentialid (tidak berhubungan dengan apa yang sudah saya tulis, saya pikir yang menarik) codeproject.com/Articles/388157/...
granadaCoder
0

Berdasarkan deskripsi Anda, pergi dengan BIGINT. Namun, indeks untuk GUID dapat menjadi non-unik, karena GUID seharusnya unik secara global.

Jimbo
sumber
-1

Jika GUID disimpan dengan benar sebagai pengidentifikasi unik seharusnya tidak memiliki masalah kinerja ... dan jika Anda dapat menggunakan GUID Sequential lebih baik ...

@Mattytommo juga memiliki poin bagus sekitar 11,5 tahun dengan menggunakan INT ...

Borik
sumber
Ya - tetapi panduan ini dibuat pada 150 basis data jarak jauh, bukan pada basis data SQL Server - jadi saya tidak dapat menggunakan sekuensialguid - tetapi terima kasih atas tanggapannya.
Roddles
Dalam hal rencana Anda menurut pendapat saya adalah suara, saya telah melakukan hal serupa pada salah satu DB yang saya kelola, saya membuat INT DENTITY (1,1) dan menetapkannya sebagai Clustered PK serta pengenal yang dapat dibaca secara manusiawi untuk data tarik ke atas dan saya simpan GUID (Indeks) sebagai pelacak untuk dapat melacak dari mana asalnya. Tapi motivasi saya lebih karena menghemat ruang ...
Borik
Banyak terima kasih dan terima kasih banyak atas jawaban dan wawasan Anda. :)
Roddles