Giải pháp tốt nhất để sửa thiết kế cơ sở dữ liệu với GUID là khóa chính


18

Tôi sau một số xác nhận về ý tưởng này để sửa chữa một cơ sở dữ liệu hoạt động kém hoặc một đề xuất tốt hơn nếu bất kỳ ai có một. Luôn luôn mở để đề xuất tốt hơn.

Tôi có một cơ sở dữ liệu rất lớn (hơn 20 triệu bản ghi tăng khoảng 1/2 triệu mỗi ngày) đang sử dụng GUID làm PK.

Một phần giám sát của tôi nhưng PK được nhóm trên máy chủ SQL và gây ra các vấn đề về hiệu suất.

Lý do cho một hướng dẫn - cơ sở dữ liệu này được đồng bộ hóa một phần với 150 cơ sở dữ liệu khác vì vậy PK cần phải là duy nhất. Đồng bộ hóa không được quản lý bởi SQL Server, thay vào đó có một quy trình tùy chỉnh được xây dựng để giữ dữ liệu đồng bộ hóa cho các yêu cầu của hệ thống - tất cả dựa trên GUID đó.

Mỗi trong số 150 cơ sở dữ liệu từ xa không lưu trữ toàn bộ dữ liệu như được lưu trữ trong Cơ sở dữ liệu SQL trung tâm. họ chỉ lưu trữ một tập hợp con dữ liệu họ thực sự yêu cầu và dữ liệu yêu cầu không phải là duy nhất đối với họ (10 trong số 150 cơ sở dữ liệu có thể có một số bản ghi giống nhau từ cơ sở dữ liệu trang web khác - ví dụ họ chia sẻ). Ngoài ra - dữ liệu thực sự được tạo ra tại các trang web từ xa - không phải ở điểm trung tâm - do đó cần có GUID.

Cơ sở dữ liệu trung tâm được sử dụng không chỉ để giữ mọi thứ đồng bộ, mà các truy vấn từ hơn 3000 người dùng sẽ được thực hiện đối với cơ sở dữ liệu phân mảnh rất lớn đó. Đây là một vấn đề lớn trong thử nghiệm ban đầu.

May mắn thay, chúng tôi chưa sống - vì vậy tôi có thể thay đổi và đưa mọi thứ ngoại tuyến nếu được yêu cầu ít nhất là một cái gì đó.

Hiệu năng của các cơ sở dữ liệu từ xa không phải là vấn đề - các tập hợp dữ liệu khá nhỏ và cơ sở dữ liệu thường không bao giờ có kích thước trên 1GB trong tổng số. Các hồ sơ được đưa trở lại hệ thống chính khá thường xuyên và được xóa khỏi các BD nhỏ hơn khi không còn cần thiết.

Hiệu suất của DB trung tâm là người lưu giữ tất cả các bản ghi là không tốt - do GUID được nhóm làm khóa chính cho nhiều bản ghi đó. Sự phân mảnh chỉ số là ra khỏi bảng xếp hạng.

Vì vậy - suy nghĩ của tôi để khắc phục vấn đề về hiệu suất là Tạo một cột mới - BIGENT IDENTITY (1,1) và sau đó thay đổi PK Clustered của cột BIGINT của bảng.

Tôi sẽ tạo một chỉ mục Non Clustered duy nhất trên trường GUID là khóa chính.

150 cơ sở dữ liệu từ xa nhỏ hơn không cần biết về PK mới trên cơ sở dữ liệu Máy chủ SQL trung tâm - nó hoàn toàn sẽ được sử dụng để tổ chức dữ liệu trong cơ sở dữ liệu và ngăn chặn hiệu suất và phân mảnh xấu.

Điều này có hoạt động và cải thiện hiệu suất của cơ sở dữ liệu SQL trung tâm và ngăn chặn địa ngục phân mảnh chỉ mục trong tương lai (ở một mức độ nào đó) không? hoặc tôi đã bỏ lỡ điều gì đó rất quan trọng ở đây sẽ nhảy lên và cắn tôi và gây ra nhiều đau buồn hơn?


2
@mattytommo Tôi đồng ý.
Paul Fleming

2
Bạn đang chạy phân mảnh chỉ mục ít nhất một lần một tuần?
Andomar

1
Bạn có bất cứ điều gì có ý nghĩa để cụm trên? Tức là, truy vấn nào nên nhanh? Nó chắc chắn sẽ không được quét phạm vi trên hướng dẫn, vì vậy thay vì chỉ chọn tự động, hãy xem xét nếu có một số cụm tối ưu thời gian truy vấn bạn có thể chọn. Nếu không, hãy tiếp tục và sử dụng bigint

2
@Borik Không phải là một ý tưởng tuyệt vời, dựa trên những gì anh ấy có và tốc độ tăng trưởng của anh ấy, anh ấy sẽ kiệt sức sau int4255 ngày (11,5 năm). Nếu anh ta làm điều đó, anh ta sẽ chỉ đổ lỗi cho bạn trong 11,5 năm;)
mattytommo

1
Một quan điểm trái ngược: Tại sao bạn nghĩ kiểu dữ liệu GUID là một vấn đề? Nó là một số nguyên 128 bit. Tại sao bạn nghĩ thay thế nó bằng số nguyên 64 bit (bigint) hoặc số nguyên 32 bit (int) sẽ tạo ra sự khác biệt đáng chú ý về tốc độ? Tôi nghĩ bạn chắc chắn nên thay đổi khóa phân cụm thành một thứ khác, để tránh tất cả việc chia trang dẫn đến phân mảnh, nhưng tôi không nghĩ bạn nên thay đổi kiểu dữ liệu trừ khi bạn rất chắc chắn rằng kiểu dữ liệu là vấn đề.
Greenstone Walker

Câu trả lời:


8

Bạn chắc chắn KHÔNG cần phải nhóm trên GUID. Nếu bạn có thứ gì đó cho phép bạn xác định duy nhất các bản ghi khác ngoài GUID đó, tôi khuyên bạn nên xem xét việc xây dựng một chỉ mục duy nhất trên trường khác đó và làm cho chỉ mục đó được nhóm lại. Nếu không, bạn có thể tự do phân cụm trên các trường khác, thậm chí sử dụng các chỉ mục nonunique. Tuy nhiên, cách tiếp cận sẽ là phân cụm tạo điều kiện tốt nhất để phân tách dữ liệu của bạn và truy vấn - vì vậy, nếu bạn có trường "vùng" hoặc thứ gì đó, có thể là một ứng cử viên cho sơ đồ phân cụm của bạn.

Vấn đề với việc thay đổi thành một BIGINTsẽ là bổ sung dữ liệu từ các cơ sở dữ liệu khác và tích hợp cơ sở dữ liệu của họ vào cửa hàng trung tâm. Nếu đây không phải là một sự cân nhắc - và sẽ không bao giờ là một sự cân nhắc - thì, vâng, BIGINTsẽ giải quyết vấn đề tái cân bằng chỉ số một cách độc đáo.

Đằng sau hậu trường, nếu bạn không chỉ định một chỉ mục được nhóm, SQL Server thực hiện nhiều điều tương tự: nó tạo ra một trường ID hàng & ánh xạ tất cả các chỉ mục khác vào đó. Vì vậy, bằng cách tự làm, bạn đang giải quyết nó giống như SQL sẽ giải quyết nó.


Trường duy nhất thực sự duy nhất trong bảng là GUD - các cột khác không phải là duy nhất và có các kết hợp các cột có thể là duy nhất để bắt đầu - nhưng theo thời gian, có một chút khả năng chúng sẽ tạo ra một bản ghi trùng lặp. Rất xa nhưng có thể đưa ra bản chất của dữ liệu. Tôi đã đọc được rằng tất cả các chỉ mục không được phân cụm khác tham chiếu chỉ mục được phân cụm để cải thiện hiệu suất tìm kiếm, v.v. Sẽ không có PK phân cụm vì GUID gây ra tác động hiệu suất? Tôi nhận thức được không gian và trong khi một mối quan tâm - hiệu suất là tối quan trọng.
Roddles

Điểm nhấn hiệu năng, nếu bạn không chỉ định một chỉ mục được nhóm, là SQL sẽ tạo một chỉ số phía sau hậu trường cho bạn và ánh xạ tất cả các chỉ mục khác vào chỉ mục đó. Vì vậy, trong trường hợp của bạn, bạn sẽ có được sự cải thiện hiệu suất bằng cách để SQL thực hiện điều đó, bởi vì ngay bây giờ bạn liên tục xáo trộn tất cả dữ liệu của mình trên đĩa để giữ trật tự sắp xếp khi thứ tự sắp xếp không quan trọng. Bạn sẽ cần nhiều không gian lưu trữ hơn, nhưng sẽ thấy một sự cải thiện lớn về lưu trữ và tối thiểu / không ảnh hưởng đến việc truy xuất.
David T. Macknet

VÌ VẬY, câu hỏi tôi đoán là nếu tôi không thực hiện BIG Cluster Cluster PK, và chỉ cần thay đổi PK thành GUID Non Clustered, ý nghĩa về hiệu suất là gì? Có các chỉ mục không được nhóm khác trên bảng sẽ được tìm kiếm thường xuyên. Điều này sẽ ảnh hưởng đến hiệu suất của những tìm kiếm đó?
Roddles

+1 Tôi cũng sẽ đề nghị ở lại với GUID. Rất khó để thay thế chúng trong các hệ thống phân tán. Chỉ mục cụm bảng lớn của bạn nên được hiển thị dựa trên cách bạn truy vấn dữ liệu.
Remus Rusanu

1
Xin chào các bạn - Chỉ là một bản cập nhật - Tôi đã thực hiện các sửa đổi và biến PK thành Không cụm trên GUID và SQL Server đang bận chèn hơn 2 triệu bản ghi vào cơ sở dữ liệu. Đồng thời dữ liệu được chèn vào, tôi có thể truy vấn cơ sở dữ liệu để biết thông tin và các truy vấn mà tại thời điểm trước khi thay đổi hết thời gian sau 10 phút, hoàn thành trong 1-2 giây. Vì vậy - làm cho PK không co cụm và không lo lắng về BIGINT dường như đã hoạt động tốt. Rất cám ơn sự đóng góp và giúp đỡ của mọi người.
Roddles 22/03/13

1

Đó là một trật tự cao.

Hãy để tôi đề nghị một cách tiếp cận người đàn ông trung bình.

Tôi đã gặp vấn đề với System.Guid.NewGuid () tạo ra các hướng dẫn ngẫu nhiên. (Tôi đã cho phép khách hàng tạo hướng dẫn riêng của họ, thay vì dựa vào cơ sở dữ liệu để tạo tuần tự).

Khi tôi chuyển sang UuidCreateSequential ở phía máy khách, hiệu suất của tôi trở nên NHIỀU hơn, đặc biệt là trên INSERT.

Đây là mã máy khách DotNet voodoo. Tôi chắc chắn tôi đã cầm đồ từ đâu đó:

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




*/

Ý TƯỞNG THAY ĐỔI:

Nếu db chính và db từ xa của bạn được "liên kết" (như trong, sp_linkserver) ...... thì bạn có thể sử dụng db chính làm "trình tạo uuid".

Bạn không muốn có được "từng cái một" của uuid, điều đó quá nhiều.

Nhưng bạn có thể lấy một bộ uuid.

Dưới đây là một số mã:

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

* /


Thú vị - và cách tiếp cận tôi đã không cân nhắc - Tôi sẽ xem xét kỹ hơn vì điều này có vẻ tốt và thực hiện một số dự án thử nghiệm. Nếu chúng ta có 150 cơ sở dữ liệu tạo ra các hướng dẫn tuần tự được báo cáo lại cho cơ sở dữ liệu trung tâm, thì điều này sẽ không gây ra sự phân mảnh vì các hướng dẫn vẫn sẽ khá ngẫu nhiên khi đưa vào cơ sở dữ liệu trung tâm. Tất nhiên trừ khi bạn có nghĩa là bỏ PK cụm và có PK không phân cụm?
Roddles

Có phải 150 cơ sở dữ liệu "từ xa" đang chèn cùng một lúc? Hay họ đang di chuyển dữ liệu theo bộ số lượng lớn vào ban đêm hoặc một cái gì đó? Vì vậy, bạn đang ở giữa một tảng đá và một nơi khó khăn. Sử dụng bigint cuối cùng sẽ hết phòng (có thể) và bạn vẫn phải nhận được giá trị duy nhất trên nhiều db. Vì vậy, đây là ý tưởng cấp tiến của tôi. 150 cơ sở dữ liệu từ xa có thể lấy UUID của họ từ một dịch vụ trung tâm không? Đó là một ý tưởng. 150 cơ sở dữ liệu từ xa có được "liên kết" (như trong sp_addlinkedserver) với cơ sở dữ liệu chính không? Sau đó, tôi có một UDF có thể được xem xét. Hãy để tôi xem nếu tôi có thể tìm thấy nó.
granadaCoder

Đây là một bài viết nói về sequentialid (không liên quan đến những gì tôi đã viết, tôi nghĩ rằng nó thú vị) codeproject.com/Articles/388157/
Lỗi

0

Dựa trên mô tả của bạn, đi với BIGINT. Tuy nhiên, chỉ mục cho GUID có thể không phải là duy nhất, vì GUID được cho là duy nhất trên toàn cầu.


-1

Nếu GUID được lưu trữ đúng cách như là định danh duy nhất thì sẽ không có bất kỳ vấn đề nào về hiệu suất ... và nếu bạn có thể sử dụng GUID tuần tự thậm chí còn tốt hơn ...

Ngoài ra @mattytommo có điểm hay khoảng 11,5 năm với việc sử dụng INT ...


Có - nhưng hướng dẫn được tạo tại cơ sở dữ liệu 150 từ xa, không phải trên cơ sở dữ liệu SQL Server - vì vậy tôi không thể sử dụng sequentialguid - nhưng cảm ơn vì đã phản hồi.
Roddles

Trong trường hợp đó, kế hoạch của bạn theo ý kiến ​​của tôi là một âm thanh, tôi đã thực hiện điều tương tự trên một trong những DB mà tôi quản lý, tôi đã tạo ra một NHIỆM VỤ INT (1,1) và đặt nó làm PK cụm cũng như định danh có thể đọc được cho dữ liệu kéo lên và tôi giữ GUID (Index) làm trình theo dõi để có thể theo dõi nơi nó bắt nguồn. Nhưng động lực của tôi là nhiều hơn từ tiết kiệm không gian ...
Borik

Rất cám ơn và đánh giá cao cho câu trả lời và hiểu biết của bạn. :)
Roddles
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.