Làm thế nào để lưu trữ uuid dưới dạng số?


77

Dựa trên câu trả lời của câu hỏi, hiệu suất UUID trong MySQL , người trả lời đề xuất lưu trữ UUID dưới dạng số chứ không phải dưới dạng chuỗi. Tôi không chắc làm thế nào nó có thể được thực hiện. Bất cứ ai có thể gợi ý cho tôi điều gì đó? Làm thế nào mã ruby ​​của tôi đối phó với điều đó?


5
Các vấn đề về hiệu suất chỉ phát sinh khi bạn đang sử dụng UUID làm khóa chính, vì UUID không phải là khóa chính hiệu quả. Tại sao bạn cần UUID? Bạn có thể giữ UUID và chỉ sử dụng autoincrement làm khóa chính không?
Thom Smith

4
@ThomSmith Re "UUID không phải là khóa chính rất hiệu quả" .. cẩn thận trích dẫn nguồn giải thích tại sao?
Pacerier

2
Đó là một phần dữ liệu lớn hơn và thường sẽ cần nhiều hướng dẫn hơn để so sánh. Nó không tuần tự, vì vậy chi phí lập chỉ mục chỉ cao hơn một chút. Và, tất nhiên, nếu bạn đang lưu trữ nó dưới dạng một chuỗi thay vì một số 128-bit, như OP dường như đang làm, tình hình sẽ tồi tệ hơn. Nó không phải là một chìa khóa khủng khiếp, nhưng tôi sẽ không sử dụng nó trừ khi có một số lý do bên ngoài để làm như vậy.
Thom Smith

Tự động gia tăng có thể gây ra sự cố với nhiều máy chủ cơ sở dữ liệu dùng chung - thường gây ra xung đột chính. UUID nhằm giải quyết những việc như vậy. Nếu bạn lưu trữ UUID của mình không phải dưới dạng văn bản mà ở dạng bin (16) thì tất nhiên bạn có UUID dạng số. So sánh nhị phân nhanh hơn văn bản. Đây là một trang web thảo luận về vấn đề này - mysql.rjweb.org/doc.php/uuid
Jeff Clayton

Câu trả lời:


109

Nếu tôi hiểu đúng, bạn đang sử dụng UUID trong cột chính của mình? Mọi người sẽ nói rằng khóa chính thông thường (số nguyên) sẽ nhanh hơn, nhưng có một cách khác là sử dụng mặt tối của MySQL. Trên thực tế, MySQL sử dụng nhị phân nhanh hơn bất kỳ thứ gì khác khi các chỉ mục được yêu cầu.

Vì UUID là 128 bit và được viết dưới dạng thập lục phân, nên rất dễ dàng để tăng tốc và lưu trữ UUID.

Đầu tiên, trong ngôn ngữ lập trình của bạn, hãy xóa dấu gạch ngang

Từ 110E8400-E29B-11D4-A716-446655440000đến 110E8400E29B11D4A716446655440000.

Bây giờ nó là 32 ký tự (như băm MD5, điều này cũng hoạt động với).

Vì một đơn BINARYtrong MySQL có kích thước 8 bit, BINARY(16)là kích thước của một UUID (8 * 16 = 128).

Bạn có thể chèn bằng cách sử dụng:

INSERT INTO Table (FieldBin) VALUES (UNHEX("110E8400E29B11D4A716446655440000"))

và truy vấn bằng cách sử dụng:

SELECT HEX(FieldBin) AS FieldBin FROM Table

Bây giờ bằng ngôn ngữ lập trình của bạn, hãy chèn lại các dấu gạch ngang ở các vị trí 9, 14, 19 và 24 để khớp với UUID ban đầu của bạn. Nếu các vị trí luôn khác nhau, bạn có thể lưu trữ thông tin đó trong trường thứ hai.

Ví dụ đầy đủ:

CREATE TABLE  `test_table` (
    `field_binary` BINARY( 16 ) NULL ,
    PRIMARY KEY (  `field_binary` )
) ENGINE = INNODB ;

INSERT INTO  `test_table` (
    `field_binary`
)
VALUES (
    UNHEX(  '110E8400E29B11D4A716446655440000' )
);

SELECT HEX(field_binary) AS field_binary FROM `test_table`

Nếu bạn muốn sử dụng kỹ thuật này với bất kỳ chuỗi hex nào, hãy luôn thực hiện length / 2với độ dài trường. Vì vậy, đối với sha512, trường sẽ là BINARY (64)vì mã hóa sha512 dài 128 ký tự.


3
@Chamnap Giả sử bạn có 10 000 hàng trong cơ sở dữ liệu của mình và chúng đã được thêm vào bằng chức năng UNHEX và bạn muốn tìm kiếm UUID 110E8400-E29B-11D4-A716-446655440000. Chỉ cần làm một cái gì đó như:SELECT * FROM test_table WHERE field_binary LIKE CONCAT("%", UNHEX('110E8400E29B11D4A716446655440000'), "%")
David Bélanger

5
Bạn có thể đọc nó nếu bạn có thời gian. Tập trung vào điểm 3: xaprb.com/blog/2009/02/12/…
David Bélanger

4
@Chamnap Có bạn có thể làm, bạn nên làm. Tôi chỉ muốn chứng minh nếu bạn muốn sử dụng caracter% với hàm UNHEX bên trong LIKE. Bạn có thể làm WHERE Field = UNHEX('110E8400E29B11D4A716446655440000'). Thay vì làm WHERE Field = 3hoặc bất cứ điều gì, bạn bọc trường bằng UNHEX khi bạn đang sử dụng chuỗi hex (để tìm kiếm, để chèn, ở đâu, cập nhật, xóa, v.v.) và bạn bọc trường bằng HEX khi bạn muốn đọc từ MySQL (lựa chọn).
David Bélanger

2
@ DavidBélanger Bạn cho biết MySQL lập chỉ mục nhị phân nhanh hơn so với int. Bất kỳ nguồn nào?
Pacerier

4
Từ ngữ gây nhầm lẫn trên loại BINARY. Một "BINARY" duy nhất trong mysql có kích thước 8 bit , đó là lý do tại sao BINARY (16) hoạt động (8 * 16 = 128, kích thước của một UUID). Nó KHÔNG "lưu trữ trong 1 bit những gì hệ thập lục phân làm trong 4 bit". Không thể nào. "Hai giá trị thập lục phân có thể được lưu trữ trong mỗi kích thước đơn vị của kiểu BINARY, bản thân nó có kích thước 8 bit, vì vậy chúng tôi cần 16 kích thước đơn vị của BINARY, do đó chúng tôi sẽ sử dụng BINARY (16)."
lilbyrdie


0

Tôi không nghĩ rằng sử dụng một hệ nhị phân là một ý tưởng hay.

Giả sử rằng bạn muốn truy vấn một số giá trị:

SELECT HEX(field_binary) AS field_binary FROM `test_table`

Nếu chúng ta đang trả về một số giá trị thì chúng ta đang gọi hàm HEX vài lần.

Tuy nhiên, vấn đề chính là vấn đề tiếp theo:

SELECT * FROM `test_table`
    where field_binary=UNHEX('110E8400E29B11D4A716446655440000')

Và sử dụng một hàm bên trong where, chỉ cần bỏ qua chỉ mục.

Cũng thế

SELECT * FROM `test_table`
    where field_binary=x'skdsdfk5rtirfdcv@#*#(&#@$9' 

Có thể dẫn đến nhiều vấn đề.


1
Bạn đã kiểm tra hiệu suất của mối quan tâm của bạn chưa? Bạn đang gợi ý rằng hiệu suất của HEX và UNHEX kém hơn các vấn đề về hiệu suất khi sử dụng trường 36 ký tự làm chỉ mục. Tôi thậm chí không cần phải kiểm tra, để biết điều đó là sai. (Nhưng vì bạn tin rằng khác, hãy kiểm tra) Thứ hai, mã bạn hiển thị không phải là cách điều này được xử lý tốt nhất. Tất cả mã DB của bạn chỉ nên liên quan đến trường 16 byte. Đừng Hex và Unhex. Chỉ cần chuyển nó đến và đi từ DB của bạn dưới dạng 16 byte đó. Thực hiện tất cả các truy vấn trực tiếp với các giá trị 16 byte đó. Chỉ khi hiển thị cho người dùng , bạn mới cần chuyển nó sang phiên bản thân thiện với người dùng.
ToolmakerSteve
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.