MySQL có thể sử dụng UUID làm KHÓA CHÍNH không?
Hãy tưởng tượng có một công cụ có thể tự động phát hiện các vấn đề về hiệu suất của JPA và Hibernate. Điều đó sẽ không tuyệt vời sao? Show
Chà, Hypersistence Optimizer là công cụ đó. Và nó hoạt động với Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus hoặc Play Framework Vì vậy, hãy tận hưởng thời gian dành cho những thứ bạn yêu thích hơn là khắc phục các vấn đề về hiệu suất trong hệ thống sản xuất của bạn vào tối thứ Bảy
Giới thiệuTrong bài viết này, chúng ta sẽ xem loại UUID (Mã định danh duy nhất toàn cầu) nào hoạt động tốt nhất cho cột cơ sở dữ liệu có ràng buộc Khóa chính Mặc dù UUID ngẫu nhiên 128 bit tiêu chuẩn là một lựa chọn rất phổ biến, nhưng bạn sẽ thấy rằng đây là một sự phù hợp khủng khiếp đối với cột Khóa chính của cơ sở dữ liệu UUID tiêu chuẩn và khóa chính cơ sở dữ liệuMã định danh duy nhất toàn cầu (UUID) là chuỗi giả ngẫu nhiên 128 bit có thể được tạo độc lập mà không cần một hệ thống tập trung duy nhất chịu trách nhiệm đảm bảo tính duy nhất của mã định danh Thông số kỹ thuật RFC 4122 xác định, được triển khai bởi các chức năng cơ sở dữ liệu hoặc ngôn ngữ lập trình khác nhau Chẳng hạn, hàm MySQL trả về số UUID phiên bản 1 Và hàm Java trả về số UUID phiên bản 4 Đối với nhiều nhà phát triển, việc sử dụng các UUID tiêu chuẩn này làm mã định danh cơ sở dữ liệu rất hấp dẫn vì
Tuy nhiên, sử dụng một UUID ngẫu nhiên làm khóa chính của bảng cơ sở dữ liệu là một ý tưởng tồi vì nhiều lý do Đầu tiên, UUID rất lớn. Mỗi bản ghi sẽ cần 16 byte cho mã định danh cơ sở dữ liệu và điều này cũng ảnh hưởng đến tất cả các cột Khóa ngoại được liên kết Thứ hai, cột Khóa chính thường có chỉ mục B+Tree được liên kết để tăng tốc độ tra cứu hoặc tham gia và chỉ mục B+Tree lưu trữ dữ liệu theo thứ tự được sắp xếp Tuy nhiên, lập chỉ mục các giá trị ngẫu nhiên bằng B+Tree gây ra nhiều vấn đề
Nếu bạn đang sử dụng SQL Server hoặc MySQL, thì điều đó thậm chí còn tệ hơn vì toàn bộ bảng về cơ bản là một chỉ mục được nhóm Và tất cả những vấn đề này cũng sẽ ảnh hưởng đến các chỉ mục phụ vì chúng lưu trữ giá trị Khóa chính trong các nút lá chỉ mục phụ Trên thực tế, hầu hết mọi chuyên gia về cơ sở dữ liệu sẽ yêu cầu bạn tránh sử dụng các UUID tiêu chuẩn làm bảng cơ sở dữ liệu Khóa chính
TSID – Mã định danh duy nhất được sắp xếp theo thời gianNếu bạn dự định lưu trữ các giá trị UUID trong cột Khóa chính, thì tốt hơn hết bạn nên sử dụng TSID (số nhận dạng duy nhất được sắp xếp theo thời gian) Một triển khai như vậy được cung cấp bởi thư viện TSID Creator OSS, cung cấp TSID 64 bit được tạo thành từ hai phần
Thành phần ngẫu nhiên có hai phần
Mã định danh nút có thể được cung cấp bởi thuộc tính hệ thống export TSIDCREATOR_NODE="12"6 khi khởi động ứng dụng -Dtsidcreator.node="12" Định danh nút cũng có thể được cung cấp thông qua biến môi trường export TSIDCREATOR_NODE="12"7 export TSIDCREATOR_NODE="12" Thư viện có sẵn trên Maven Central, vì vậy bạn có thể lấy nó thông qua phần phụ thuộc sau
Bạn có thể tạo một đối tượng export TSIDCREATOR_NODE="12"8 có thể sử dụng tối đa 256 nút như thế này Tsid tsid = TsidCreator.getTsid256(); Từ đối tượng export TSIDCREATOR_NODE="12"8, chúng ta có thể trích xuất các giá trị sau
Để trực quan hóa các giá trị này, chúng ta có thể in chúng vào nhật ký long tsidLong = tsid.toLong(); String tsidString = tsid.toString(); long tsidMillis = tsid.getUnixMilliseconds(); LOGGER.info( "TSID numerical value: {}", tsidLong ); LOGGER.info( "TSID string value: {}", tsidString ); LOGGER.info( "TSID time millis since epoch value: {}", tsidMillis ); Và chúng tôi nhận được đầu ra sau TSID numerical value: 388400145978465528 TSID string value: 0ARYZVZXW377R TSID time millis since epoch value: 1670438610927 Khi tạo ra mười giá trị for (int i = 0; i < 10; i++) { LOGGER.info( "TSID numerical value: {}", TsidCreator.getTsid256().toLong() ); } Chúng ta có thể thấy rằng các giá trị đang tăng đơn điệu TSID numerical value: 388401207189971936 TSID numerical value: 388401207189971937 TSID numerical value: 388401207194165637 TSID numerical value: 388401207194165638 TSID numerical value: 388401207194165639 TSID numerical value: 388401207194165640 TSID numerical value: 388401207194165641 TSID numerical value: 388401207194165642 TSID numerical value: 388401207194165643 TSID numerical value: 388401207194165644 Tuyệt vời, phải không? Sử dụng TSID trong ứng dụng của bạnBởi vì các nhà máy TSID mặc định được cung cấp thông qua tiện ích 1 đi kèm với bộ tạo giá trị ngẫu nhiên được đồng bộ hóa, nên tốt hơn là sử dụng một 2 tùy chỉnh cung cấp các tối ưu hóa sau
Vì vậy, chúng ta có thể định nghĩa 4 sau đây cung cấp cho chúng ta một 2 để sử dụng bất cứ khi nào chúng ta muốn tạo một đối tượng export TSIDCREATOR_NODE="12"8 mới public static class TsidUtil { public static final String TSID_NODE_COUNT_PROPERTY = "tsid.node.count"; public static final String TSID_NODE_COUNT_ENV = "TSID_NODE_COUNT"; public static TsidFactory TSID_FACTORY; static { String nodeCountSetting = System.getProperty( TSID_NODE_COUNT_PROPERTY ); if(nodeCountSetting == null) { nodeCountSetting = System.getenv( TSID_NODE_COUNT_ENV ); } int nodeCount = nodeCountSetting != null ? Integer.parseInt(nodeCountSetting) : 256; int nodeBits = (int) (Math.log(nodeCount) / Math.log(2)); TSID_FACTORY = TsidFactory.builder() .withRandomFunction(length -> { final byte[] bytes = new byte[length]; ThreadLocalRandom.current().nextBytes(bytes); return bytes; }) .withNodeBits(nodeBits) .build(); } } Và để chứng minh rằng chúng ta không bị xung đột ngay cả khi sử dụng nhiều luồng trên cùng một nút ứng dụng, chúng ta có thể sử dụng trường hợp thử nghiệm sau int threadCount = 16; int iterationCount = 100_000; CountDownLatch endLatch = new CountDownLatch(threadCount); ConcurrentMap Khi chạy thử nghiệm này, chúng tôi nhận được kết quả như sau export TSIDCREATOR_NODE="12"0 Không chỉ việc tạo TSID không bị xung đột mà chúng tôi còn tạo được 1. 6 triệu id trong vòng chưa đầy 800 mili giây Sử dụng TSID làm giá trị Khóa chínhVì TSID là một số 64-bit được sắp xếp theo thời gian nên cách tốt nhất để lưu trữ nó trong cơ sở dữ liệu là sử dụng loại cột 7 export TSIDCREATOR_NODE="12"1 Và, về phía ứng dụng, bạn cần sử dụng một số 64 bit, chẳng hạn như loại đối tượng Java 8 export TSIDCREATOR_NODE="12"2 Đó là nó
Phần kết luậnSử dụng UUID tiêu chuẩn làm giá trị Khóa chính không phải là ý tưởng hay trừ khi các byte đầu tiên tăng đơn điệu Vì lý do này, sử dụng TSID được sắp xếp theo thời gian là một ý tưởng tốt hơn nhiều. Nó không chỉ yêu cầu một nửa số byte như một UUID tiêu chuẩn, mà nó còn phù hợp hơn với vai trò là khóa chỉ mục B+Tree Mặc dù SQL Server cung cấp GUID được sắp xếp theo thời gian thông qua 9, nhưng kích thước của GUID là 128 bit, do đó, nó lớn gấp đôi TSID Vấn đề tương tự xảy ra với phiên bản 7 của đặc tả UUID, cung cấp UUID được sắp xếp theo thời gian. Tuy nhiên, nó sử dụng cùng một định dạng chuẩn (128 bit), quá lớn. Tác động của việc lưu trữ cột Khóa chính được khuếch đại bởi mọi cột Khóa ngoại tham chiếu Nếu tất cả các khóa Chính của bạn là UUID 128 bit, thì các chỉ mục Khóa chính và Khóa ngoại sẽ cần nhiều dung lượng, cả trên đĩa và trong bộ nhớ cơ sở dữ liệu, vì Vùng đệm chứa cả trang bảng và trang chỉ mục Theo dõi @vlad_mihalcea Chèn chi tiết về cách thông tin sẽ được xử lý TẢI NGAY Có liên quanLoại. Cơ sở dữ liệu Thẻ. BTree, chỉ mục nhóm, Khóa chính, TSID, UUID ← Bản tin Java Persistence hiệu suất cao, Số 45 Trình nghe thực thể ngủ đông dữ liệu mùa xuân → 22 Nhận xét về “ Loại UUID tốt nhất cho Khóa chính cơ sở dữ liệu ”
|