- vừa được xem lúc

Sử dụng Sequence GUID trong PostgreSQL

0 0 15

Người đăng: Hoàng Linh

Theo Viblo Asia

Tại sao lại sử dụng GUID để làm primary key

Ưu điểm

  • Độc lập với ngữ cảnh: GUID là một chuỗi số duy nhất, không phụ thuộc vào ngữ cảnh nào, do đó nó có thể được tạo ra mà không cần phải trông chờ vào cơ sở dữ liệu.
  • Phân phối đồng đều: GUID được tạo ra để đảm bảo tính ngẫu nhiên và không trùng lặp trên toàn thế giới, do đó nó phân phối đều hơn so với các khóa tự tăng (auto-increment) trong môi trường phân tán.
  • Bảo mật tương đối: GUID không dễ đoán được, điều này có thể mang lại một mức độ bảo mật tương đối khi so sánh với các khóa tự tăng.
  • Tích hợp dễ dàng: GUID có thể được sử dụng với nhiều loại cơ sở dữ liệu và ngôn ngữ lập trình.

Nhược điểm

  • Kích thước lớn: GUID có kích thước lớn hơn so với các khóa tự tăng, điều này có thể làm tăng kích thước của bảng và dẫn đến tăng tải cho cơ sở dữ liệu.
  • Hiệu suất không tốt: Do kích thước lớn và tính không liên tục của GUID, việc sử dụng chúng làm khóa chính có thể ảnh hưởng đến hiệu suất của các truy vấn, đặc biệt là trong các bảng lớn.
  • Khó đọc và nhớ: GUID là một chuỗi số ngẫu nhiên, không dễ đọc hoặc nhớ, điều này có thể làm cho việc thao tác với dữ liệu trở nên khó khăn hơn đối với con người.
  • Cần tăng cường bảo mật: Mặc dù GUID khó đoán được, nhưng không có gì ngăn chặn việc sử dụng một GUID khác nhau từ phía người dùng, do đó cần phải cân nhắc vấn đề bảo mật cẩn thận hơn.

Ngoài ra, khi sử dụng GUID làm primary key, việc tạo index trên bảng sẽ gặp nhiều vấn đề bởi tính phân phối ngẫu nhiên của GUID.

Sequence GUID - một cứu tinh mới

Sequence GUID là một cách để tạo ra các GUID (Globally Unique Identifier) theo một trình tự cụ thể.

Thông thường, GUID được tạo ra thông qua các thuật toán đảm bảo tính ngẫu nhiên và độc lập của chúng. Tuy nhiên, trong một số trường hợp, đặc biệt là khi cần sắp xếp và lập trình logic theo thứ tự, việc tạo GUID theo một trình tự nhất định có thể hữu ích.

Sequence GUID thường được tạo ra bằng cách kết hợp các thành phần như timestamp, node ID, hoặc các yếu tố khác để đảm bảo tính duy nhất và tăng dần. Điều này giúp cho việc sắp xếp và quản lý dữ liệu dễ dàng hơn trong một số tình huống.

Trong SQL Server, chúng ta có thể tạo và sử dụng các Sequence GUID, vì nó được tạo theo một trình tự cụ thể nên giải quyết được các vấn đề về index, order by...vv

Entity Frameworks SequentialGuidValueGenerator cung cấp method để tạo sequential GUIDs cho SQL Server

image.png

Với PostgreSQL thì sao ?

Và với tất cả những tính năng trên, một ngày đẹp trời sếp bảo team apply vào cho dự án hiện tại. Anh em rất phấn khởi vì idea này cũng hay, và khi apply vào thì lại không chạy, GUID vẫn gen ngẫu nhiên, vì sao thế ? Sau một hồi tìm hiểu thì có vẻ cơ chế của PostgreSQL không phù hợp với solution này, bởi vì Identifier của SQL Server làm việc rất tốt để sinh ra mã sequence GUID, nhưng PostgreSQL thì không. Và với yêu cầu của sếp, sau khi tìm hiểu thì có thể giải quyết được bằng việc sử dụng https://uuid7.com/ với các tiêu chí mà nó mang lại, đã khá ổn.

Benefits of UUIDv7:

  • Time-Sortability: As mentioned, UUIDv7 values are time-sortable, which means you can sort them in increasing order based on when they were generated. This makes time-based queries more efficient and intuitive.
  • Precise Timestamping: With a granularity of up to 50 nanoseconds as of previous drafts (but a default of 1 millisecond as of writing, see draft RFC4122), UUIDv7 offers excellent precision. This, when combined with the randomness, essentially guarantees that collisions (even among globally distributed systems!) are impossible.
  • Global Uniqueness: Like other UUIDs, UUIDv7 ensures global uniqueness. This means you can generate IDs independently across different systems or nodes, and they won't collide.

Why UUIDv7 is Better for Databases:

  • Natural Sorting: Traditional databases often require additional timestamp columns to sort records based on creation time. With UUIDv7, you can achieve this sorting using the UUID itself, eliminating the need for extra columns.
  • Optimized Indexing: Since UUIDv7 is time-sortable, database indexing mechanisms can better optimize the storage and retrieval processes, leading to faster query times especially for time-based queries.
  • Concurrency and Distribution: In distributed systems, generating unique, sequential IDs can be a challenge. UUIDv7 can be generated concurrently across multiple nodes without the risk of collisions, making it suitable for distributed architectures.
  • Reduced Overhead: Unlike UUIDv1, which can expose the MAC address of the machine where the UUID was generated (raising privacy concerns), UUIDv7 doesn't have this drawback, reducing the overhead of obscuring or anonymizing this data.
  • Flexibility: Databases that support binary storage can store UUIDv7 efficiently, and they can be easily encoded into other formats like strings if required.

Và, dự án của Team đang chạy là NET 8 + PostgreSQL, với PostgreSQL thì có cung cấp 1 extensions chính thống là : UUID-OSSP nhưng chỉ tạo được tới v5, vậy có vẻ chúng ta phải xử lý mã nguồn 1 chút để apply V7 vào.

Dưới đây là cách thức refactor của mình cho dự án

Sử dụng UUID-Extensions package trên Nuget để sinh ra mã UUID v7 Khai báo trong hàm khởi tạo của BaseEntity, để đảm bảo khi dev sử dụng cú pháp Object-Initialized thì không can thiệp vào Id

 public virtual Guid Id { get; private set; } public BaseEntity() { var guid = Uuid7.Guid(); this.Id = guid; }
public void SetId()
{ this.Id = Uuid7.Guid();
}

Khai báo tầm vực cho biến Id là private set, chỉ chấp nhận thay đổi Id trong hàm khởi tạo hoặc setter, không chấp nhận truyền id từ bên ngoài

Để ngăn chặn việc PostgreSQL tự tạo GUID cho rows, dẫn đến mất ưu điểm của V7, ta sẽ override lại SaveChangesAsync() và thực hiện validate Id

public override int SaveChanges(bool acceptAllChangesOnSuccess)
{ AddSequenceGuid(); return base.SaveChanges(acceptAllChangesOnSuccess);
} private void AddSequenceGuid()
{ var entities = ChangeTracker.Entries().Where(x => x.State == EntityState.Added && x.Entity is BaseEntity); foreach (var entityEntry in entities) { var entity = (BaseEntity)entityEntry.Entity; if (UuidHelper.ValidateUuidV7(entity.Id) is false) { entity.SetId(); } }
}
public static class UuidHelper
{ private static readonly System.Text.RegularExpressions.Regex Uuid7Re = new System.Text.RegularExpressions.Regex(@"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", RegexOptions.IgnoreCase); public static DateTime ParseUuid7Date(string uuid) { if (uuid == null || !Uuid7Re.IsMatch(uuid)) { throw new ArgumentException($"Expected UUIDv7. Received: {uuid ?? "null"}"); } string timestampHex = uuid.Substring(0, 13).Replace("-", ""); long timestamp = Convert.ToInt64(timestampHex, 16); return DateTimeOffset.FromUnixTimeMilliseconds(timestamp).UtcDateTime; } public static bool ValidateUuidV7(string uuid) { try { var result = ParseUuid7Date(uuid); return true; } catch { return false; } } public static bool ValidateUuidV7(Guid uuid) { try { var result = ParseUuid7Date(uuid.ToString()); return true; } catch { return false; } }
}

Chúng ta cần kiểm tra trường Id đã chuẩn UUID V7 chưa, nếu chưa thì cần set lại cho nó, trong trường hợp nó đang là Guid.Empty

Như vậy, chúng ta đã có thể sử dụng được UUID V7 như một Sequence GUID trong PostgreSQL và kế thừa được các ưu điểm như trên.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Stored Procedure trong SQL Server

Stored Procedure là 1 phần không thể thiếu của SQL Server. Chúng có thể hỗ trợ rất nhiều cho lập trình và cấu hình cơ sở dữ liệu.

0 0 164

- vừa được xem lúc

sử dụng index trong sql query

Index là một trong những yếu tố quan trọng nhất góp phần vào việc nâng cao hiệu suất của cơ sở dữ liệu. Index trong SQL tăng tốc độ của quá trình truy vấn dữ liệu bằng cách cung cấp phương pháp truy xuất nhanh chóng tới các dòng trong các bảng, tương tự như cách mà mục lục của một cuốn sách giúp bạn

0 0 192

- vừa được xem lúc

Hướng dẫn sửa lỗi không cài được SQL Server

Hôm qua do yêu cầu môn học, mình có cài lại Microsoft SQL Server. Trước đó mình có cài rồi, nhưng rồi lâu không dùng nên gỡ ra cho nhẹ máy. Bây giờ có dịp cần nên mình mới cài lại. Chi tiết lỗi mình gặp phải.

0 0 134

- vừa được xem lúc

Bạn nên tránh sử dụng Soft Delete khi có thể, và đây là lý do tại sao

Con người luôn luôn mắc sai lầm. Vì vậy, việc "lo xa" trước mọi tình huống xấu nhất chưa bao giờ là thừa.

0 0 140

- vừa được xem lúc

Sử dụng trigger trong SQL qua ví dụ cơ bản.

Trigger là gì . Cú pháp của Trigger. CREATE TRIGGER tên_trigger ON tên_bảng. FOR {DELETE, INSERT, UPDATE}.

0 0 161

- vừa được xem lúc

Khác biệt giữa khóa chính và khóa ngoại trong SQL

Các khoá chính và khóa ngoại là hai loại ràng buộc có thể được sử dụng để thực thi toàn vẹn dữ liệu trong các bảng SQL Server và đây là những đối tượng cơ sở dữ liệu quan trọng. Trong bài này, tôi muố

0 0 149