Có sự khác biệt hiệu năng THỰC SỰ giữa các khóa chính INT và VARCHAR không?


174

Có sự khác biệt hiệu suất có thể đo được giữa việc sử dụng INT so với VARCHAR làm khóa chính trong MySQL không? Tôi muốn sử dụng VARCHAR làm khóa chính cho danh sách tham chiếu (nghĩ rằng Hoa Kỳ, Mã quốc gia) và đồng nghiệp sẽ không nhúc nhích trên INT AUTO_INCREMENT làm khóa chính cho tất cả các bảng.

Lập luận của tôi, như chi tiết ở đây , là sự khác biệt về hiệu năng giữa INT và VARCHAR là không đáng kể, vì mỗi tham chiếu khóa ngoại INT sẽ yêu cầu THAM GIA để hiểu ý nghĩa của tham chiếu, khóa VARCHAR sẽ trực tiếp trình bày thông tin.

Vì vậy, có ai có kinh nghiệm với trường hợp sử dụng cụ thể này và các mối quan tâm về hiệu suất liên quan đến nó không?


3
Tôi đã tạo một bài đăng với câu trả lời "không" với một số chi tiết về các bài kiểm tra tôi đã chạy ... nhưng đó là SQL Server, không phải MySQL. Vì vậy, tôi đã xóa câu trả lời của tôi.
Timothy Khouri

17
@Timothy - bạn không nên xóa nó. Tôi đang trong quá trình bỏ phiếu. Hầu hết các máy chủ cơ sở dữ liệu SQL có các trình hoạch định truy vấn tương tự và các tắc nghẽn hiệu suất tương tự.
Paul Tomblin

9
@Timothy vui lòng đăng lại kết quả của bạn.
Jake McGraw

2
Vì vậy, nhiều ý kiến ​​và câu trả lời cho rằng các khóa được sử dụng để tham gia. Họ không phải. Các khóa được sử dụng để thống nhất dữ liệu - để tránh các hàng trùng lặp, (nhiều hơn một hàng đại diện cho cùng một thực thể). Bất kỳ cột (hoặc bộ cột) nào cũng có thể được sử dụng trong một liên kết và để đảm bảo rằng phép nối đó là một số không hoặc nhiều cột [s] chỉ cần là duy nhất. Bất kỳ chỉ số duy nhất đảm bảo rằng, và nó không cần phải có ý nghĩa.
Charles Bretana

Câu trả lời:


78

Bạn nêu rõ rằng bạn có thể tránh được một số truy vấn đã tham gia bằng cách sử dụng khóa được gọi là khóa tự nhiên thay vì khóa thay thế . Chỉ bạn mới có thể đánh giá xem lợi ích của việc này có ý nghĩa trong ứng dụng của bạn hay không.

Đó là, bạn có thể đo các truy vấn trong ứng dụng quan trọng nhất để được nhanh chóng, bởi vì chúng hoạt động với khối lượng dữ liệu lớn hoặc chúng được thực hiện rất thường xuyên. Nếu các truy vấn này có lợi từ việc loại bỏ một phép nối và không bị ảnh hưởng bởi việc sử dụng khóa chính varchar, thì hãy thực hiện nó.

Không sử dụng một trong hai chiến lược cho tất cả các bảng trong cơ sở dữ liệu của bạn. Có thể trong một số trường hợp, khóa tự nhiên sẽ tốt hơn, nhưng trong những trường hợp khác, khóa thay thế sẽ tốt hơn.

Những người khác đưa ra một điểm tốt là trong thực tế, rất hiếm khi một khóa tự nhiên không bao giờ thay đổi hoặc có các bản sao, vì vậy các khóa thay thế thường đáng giá.


3
Và đôi khi, (imho, thường), cả hai đều tốt hơn, thay thế để sử dụng cho các tham chiếu FK trong các bảng khác và cho Joins, và khóa tự nhiên để đảm bảo tính nhất quán của dữ liệu
Charles Bretana

@CharlesBretana Thật thú vị. Việc sử dụng khóa tự nhiên để thống nhất dữ liệu dọc theo FK có phải là một thông lệ không? Suy nghĩ đầu tiên của tôi là bộ nhớ bổ sung sẽ được yêu cầu trên các bảng lớn có thể không làm cho nó đáng giá. Bất kỳ thông tin được đánh giá cao. FYI - Tôi có một nền tảng lập trình khá, nhưng trải nghiệm SQL của tôi chủ yếu giới hạn ở các truy vấn CHỌN
Rob

2
@CharlesBretana Khi tôi đọc "lưu trữ cả hai", tôi nghĩ rằng "dư thừa" và "không được chuẩn hóa", bằng với "Công cụ này có thể bị hỏng" và "Tôi phải đảm bảo cả hai đều được thay đổi nếu một trong số đó được thay đổi". Nếu bạn có dự phòng, cần có một lý do rất chính đáng (như hiệu suất hoàn toàn không thể chấp nhận được) vì sự dư thừa luôn tiềm ẩn khiến dữ liệu của bạn trở nên không nhất quán.
jpmc26

3
@ jpmc26, Hoàn toàn KHÔNG có vấn đề dư thừa hoặc bình thường hóa liên quan. Khóa thay thế không có kết nối có ý nghĩa với các giá trị trong khóa tự nhiên, do đó không bao giờ cần phải thay đổi. Khi bình thường hóa, bạn đang nói về vấn đề bình thường hóa nào? Chuẩn hóa áp dụng cho các thuộc tính có ý nghĩa của một mối quan hệ; giá trị số của khóa thay thế, (thực sự, chính khái niệm về khóa thay thế) nằm hoàn toàn bên ngoài bối cảnh của bất kỳ chuẩn hóa nào.
Charles Bretana

1
Và để trả lời câu hỏi khác của bạn, cụ thể là về bảng trạng thái, nếu bạn có khóa thay thế trên bảng này, với các giá trị, giả sử, từ 1 đến 50, nhưng bạn KHÔNG đặt chỉ mục hoặc khóa duy nhất khác vào mã bưu chính của tiểu bang, (và, theo ý kiến ​​của tôi, về tên tiểu bang), vậy thì điều gì để ngăn ai đó nhập hai hàng với các giá trị khóa thay thế khác nhau nhưng có cùng mã bưu chính và / hoặc tên tiểu bang? Ứng dụng khách sẽ xử lý nó như thế nào nếu có hai hàng với 'NJ', 'New Jersey'? Khóa tự nhiên đảm bảo tính nhất quán dữ liệu!
Charles Bretana

81

Đó không phải là về hiệu suất. Đó là về những gì làm cho một khóa chính tốt. Độc đáo và không thay đổi theo thời gian. Bạn có thể nghĩ rằng một thực thể như mã quốc gia không bao giờ thay đổi theo thời gian và sẽ là một ứng cử viên tốt cho khóa chính. Nhưng kinh nghiệm cay đắng là hiếm khi như vậy.

INT AUTO_INCREMENT đáp ứng điều kiện "duy nhất và không thay đổi theo thời gian". Do đó ưu tiên.


25
Thật. Một trong những cơ sở dữ liệu lớn nhất của tôi có các mục nhập cho Nam Tư và Liên Xô. Tôi rất vui vì chúng không phải là khóa chính.
Paul Tomblin

8
@Steve, vậy tại sao cú pháp hỗ trợ SQL của ANSI cho ON CẬP NHẬT CASCADE?
Bill Karwin

5
Bất biến không phải là một yêu cầu của một chìa khóa. Trong mọi trường hợp, khóa thay thế đôi khi cũng thay đổi. Không có gì sai khi thay đổi phím nếu bạn cần.
nvogel

9
Paul, vậy bạn đã đổi Liên Xô thành Nga trong cơ sở dữ liệu của bạn? Và giả vờ rằng SU không bao giờ tồn tại? Và tất cả các tài liệu tham khảo về SU bây giờ chỉ đến Nga?
Dainius

6
@alga Tôi sinh ra ở SU nên tôi biết nó là gì.
Dainius

52

Tôi đã có một chút khó chịu vì thiếu điểm chuẩn cho trực tuyến này, vì vậy tôi đã tự mình chạy thử.

Lưu ý rằng mặc dù tôi không làm điều đó một cách cơ bản thường xuyên, vì vậy vui lòng kiểm tra thiết lập và các bước của tôi để biết bất kỳ yếu tố nào có thể ảnh hưởng đến kết quả ngoài ý muốn và gửi những lo ngại của bạn trong các bình luận.

Các thiết lập như sau:

  • CPU Intel® Core ™ i7-7500U @ 2.70GHz × 4
  • RAM 15,6 GiB, trong đó tôi đảm bảo khoảng 8 GB là miễn phí trong quá trình thử nghiệm.
  • Ổ SSD 148,6 GB, có nhiều dung lượng trống.
  • Ubuntu 16.04 64-bit
  • MySQL Ver 14,14 Phân phối 5.7.20, cho Linux (x86_64)

Những cái bàn:

create table jan_int (data1 varchar(255), data2 int(10), myindex tinyint(4)) ENGINE=InnoDB;
create table jan_int_index (data1 varchar(255), data2 int(10), myindex tinyint(4), INDEX (myindex)) ENGINE=InnoDB;
create table jan_char (data1 varchar(255), data2 int(10), myindex char(6)) ENGINE=InnoDB;
create table jan_char_index (data1 varchar(255), data2 int(10), myindex char(6), INDEX (myindex)) ENGINE=InnoDB;
create table jan_varchar (data1 varchar(255), data2 int(10), myindex varchar(63)) ENGINE=InnoDB;
create table jan_varchar_index (data1 varchar(255), data2 int(10), myindex varchar(63), INDEX (myindex)) ENGINE=InnoDB;

Sau đó, tôi đã lấp đầy 10 triệu hàng trong mỗi bảng bằng một tập lệnh PHP có bản chất là như thế này:

$pdo = get_pdo();

$keys = [ 'alabam', 'massac', 'newyor', 'newham', 'delawa', 'califo', 'nevada', 'texas_', 'florid', 'ohio__' ];

for ($k = 0; $k < 10; $k++) {
    for ($j = 0; $j < 1000; $j++) {
        $val = '';
        for ($i = 0; $i < 1000; $i++) {
            $val .= '("' . generate_random_string() . '", ' . rand (0, 10000) . ', "' . ($keys[rand(0, 9)]) . '"),';
        }
        $val = rtrim($val, ',');
        $pdo->query('INSERT INTO jan_char VALUES ' . $val);
    }
    echo "\n" . ($k + 1) . ' millon(s) rows inserted.';
}

Đối với intcác bảng, bit ($keys[rand(0, 9)])được thay thế bằng chỉ rand(0, 9)và đối với varcharcác bảng, tôi đã sử dụng tên trạng thái đầy đủ của Hoa Kỳ mà không cắt hoặc mở rộng chúng thành 6 ký tự. generate_random_string()tạo ra một chuỗi ngẫu nhiên gồm 10 ký tự.

Sau đó, tôi chạy trong MySQL:

  • SET SESSION query_cache_type=0;
  • Đối với jan_intbảng:
    • SELECT count(*) FROM jan_int WHERE myindex = 5;
    • SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
  • Đối với các bảng khác, tương tự như trên, với myindex = 'califo'cho charbảng và myindex = 'california'cho varcharbảng.

Thời gian của BENCHMARKtruy vấn trên mỗi bảng:

  • jan_int: 21.30 giây
  • jan_int_index: 18,79 giây
  • jan_char: 21,70 giây
  • jan_char_index: 18,85 giây
  • tháng một: 21,76 giây
  • jan_varchar_index: 18,86 giây

Về kích thước bảng và chỉ mục, đây là đầu ra của show table status from janperformancetest;(w / một vài cột không được hiển thị):

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Name              | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Collation              |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| jan_int           | InnoDB |      10 | Dynamic    | 9739094 |             43 |   422510592 |               0 |            0 |   4194304 |           NULL | utf8mb4_unicode_520_ci |  
| jan_int_index     | InnoDB |      10 | Dynamic    | 9740329 |             43 |   420413440 |               0 |    132857856 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_char          | InnoDB |      10 | Dynamic    | 9726613 |             51 |   500170752 |               0 |            0 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_char_index    | InnoDB |      10 | Dynamic    | 9719059 |             52 |   513802240 |               0 |    202342400 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_varchar       | InnoDB |      10 | Dynamic    | 9722049 |             53 |   521142272 |               0 |            0 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_varchar_index | InnoDB |      10 | Dynamic    | 9738381 |             49 |   486539264 |               0 |    202375168 |   7340032 |           NULL | utf8mb4_unicode_520_ci | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

Kết luận của tôi là không có sự khác biệt về hiệu năng cho trường hợp sử dụng cụ thể này.


Tôi biết bây giờ đã muộn, nhưng tôi đã tò mò muốn xem kết quả nếu bạn đã chọn một chuỗi ít lý tưởng hơn cho điều kiện nơi. "califo [rnia]" là lý tưởng vì nó có thể loại bỏ sự không phù hợp sau khi so sánh ký tự đầu tiên, chỉ cần kiểm tra thêm về các trận đấu thực tế; một cái gì đó như "newham" sẽ cho kết quả thú vị hơn vì nó sẽ mới để so sánh nhiều nhân vật hơn để loại bỏ tất cả sự không phù hợp. Ngoài ra, giới hạn số nguyên của bạn theo cách đó cũng ngăn chặn tỷ lệ cược với chúng, tôi sẽ cung cấp cho chúng ít nhất 26 giá trị.
Uueerdo

15
Thật ngạc nhiên khi trong một câu hỏi 10 năm tuổi, đây chỉ là một trong hai câu trả lời không chỉ là suy đoán và dựa vào điểm chuẩn thực tế.
Adrian Baker

1
Nhưng các bảng của bạn không có khóa chính, mà thực sự trong InnoDB là cấu trúc dữ liệu được sắp xếp. Tốc độ giữa sắp xếp số nguyên và sắp xếp chuỗi phải khác nhau.
Melkor

1
@Melkor Điểm công bằng mà tôi sử dụng INDEXthay vì PRIMARY KEY. Tôi không nhớ lý do của mình - tôi có thể giả định PRIMARY KEYchỉ là một INDEXràng buộc duy nhất. Tuy nhiên, đọc phần về cách mọi thứ được lưu trữ trong InnoDB trong federico-razzoli.com/primary-key-in-innodb , tôi nghĩ rằng kết quả của tôi vẫn áp dụng cho các khóa chính và trả lời câu hỏi về chênh lệch hiệu suất tra cứu giá trị. Ngoài ra, nhận xét của bạn đề nghị xem xét hiệu suất của các thuật toán sắp xếp , không áp dụng cho trường hợp sử dụng mà tôi điều tra, đó là tìm kiếm các giá trị trong một tập hợp.
Jan Żankowski

1
Hoạt động tra cứu cũng yêu cầu so sánh trên trường khóa chính (như tìm kiếm nhị phân), trong đó int nên nhanh hơn một chút so với varchar. Nhưng như các thử nghiệm của bạn đã đề xuất, điều đó không rõ ràng (hoặc có thể do bạn không có khóa chính nên các truy vấn đều chậm hơn). Tôi nghĩ đó là điều tương tự khi chèn và tra cứu.
Melkor

38

Phụ thuộc vào độ dài .. Nếu varchar sẽ có 20 ký tự và int là 4, thì nếu bạn sử dụng int, chỉ mục của bạn sẽ có FIVE gấp nhiều lần trên mỗi trang của không gian chỉ mục trên đĩa ... Điều đó có nghĩa là đi qua chỉ mục sẽ yêu cầu 1/5 số lần đọc vật lý và / hoặc logic ..

Vì vậy, nếu hiệu suất là một vấn đề, nếu có cơ hội, hãy luôn sử dụng khóa không có ý nghĩa tích hợp (được gọi là thay thế) cho các bảng của bạn và cho Khóa ngoài tham chiếu các hàng trong các bảng này ...

Đồng thời , để đảm bảo tính nhất quán của dữ liệu, mỗi bảng có vấn đề cũng cần có khóa thay thế không phải là số có ý nghĩa, (hoặc Chỉ mục duy nhất) để đảm bảo rằng các hàng trùng lặp không thể được chèn (trùng lặp dựa trên các thuộc tính bảng có ý nghĩa).

Đối với mục đích sử dụng cụ thể mà bạn đang nói đến (như tra cứu trạng thái) thực sự không có vấn đề gì vì kích thước của bảng quá nhỏ .. Nói chung, không có tác động nào đến hiệu suất từ ​​các chỉ số trên các bảng có ít hơn vài nghìn hàng. ..


Chắc chắn rồi? Arent các định dạng dữ liệu hàng nhất dựa trên? Có dữ liệu khác ngoài các phím. Không phải là yếu tố 5 không tưởng?
ManuelSchneid3r

1
@ manuelSchneid3r, Cái gì? không tưởng? Không, yếu tố 5 không phải là "không tưởng". Nó chỉ là 20 chia cho 4. Và "hàng định dạng dữ liệu dựa trên" nghĩa là gì? Các chỉ số không phải là "hàng dựa", chúng là các cấu trúc cây cân bằng.
Charles Bretana

36

Tuyệt đối không.

Tôi đã thực hiện một số ... một vài ... kiểm tra hiệu suất giữa INT, VARCHAR và CHAR.

Bảng kỷ lục 10 triệu với KHÓA CHÍNH (duy nhất và được nhóm) có cùng tốc độ và hiệu suất (và chi phí phụ) cho dù tôi sử dụng loại nào trong ba loại.

Điều đó đang được nói ... sử dụng bất cứ điều gì là tốt nhất cho ứng dụng của bạn. Đừng lo lắng về hiệu suất.


42
vô nghĩa mà không biết varchars dài bao nhiêu ... Nếu chúng là 100 byte widem thì đảm bảo bạn sẽ không có hiệu suất tương đương với int 4 byte
Charles Bretana

6
Nó cũng sẽ giúp biết cơ sở dữ liệu nào bạn đang sử dụng và phiên bản cơ sở dữ liệu nào. Điều chỉnh hiệu suất hầu như luôn luôn hoạt động và được cải thiện từ phiên bản này sang phiên bản khác.
Dave Black

VARCHAR chắc chắn quan trọng đối với kích thước chỉ mục. Và chỉ số xác định bao nhiêu có thể phù hợp trong bộ nhớ. Và các chỉ mục trong bộ nhớ là rất xa, nhanh hơn nhiều so với những chỉ số không có. Có thể là đối với hàng 10m của bạn, bạn có sẵn 250 MB bộ nhớ cho chỉ mục đó và vẫn ổn. Nhưng nếu bạn có 100m hàng, bạn sẽ kém hơn trong bộ nhớ đó.
Paul Draper

9

Đối với các mã ngắn, có lẽ không có sự khác biệt. Điều này đặc biệt đúng vì bảng chứa các mã này có thể rất nhỏ (nhiều nhất là vài nghìn hàng) và không thay đổi thường xuyên (lần cuối cùng chúng tôi đã thêm một Tiểu bang mới của Hoa Kỳ).

Đối với các bảng lớn hơn với biến thể rộng hơn giữa các phím, điều này có thể nguy hiểm. Ví dụ, hãy suy nghĩ về việc sử dụng địa chỉ email / tên người dùng từ bảng Người dùng. Điều gì xảy ra khi bạn có một vài triệu người dùng và một số người dùng đó có tên dài hoặc địa chỉ email. Bây giờ bất cứ khi nào bạn cần tham gia bảng này bằng phím đó, nó sẽ trở nên đắt hơn nhiều.


2
Bạn có biết chắc chắn rằng điều này sẽ đắt tiền? Hay bạn chỉ đang đoán?
Steve McLeod

Tất nhiên nó phụ thuộc vào việc triển khai rdbms, nhưng theo những gì tôi hiểu thì hầu hết các máy chủ sẽ giữ nguyên giá trị thực tế cho mục đích lập chỉ mục. Mặc dù vậy, và ngay cả khi đó là một hàm băm tương đối ngắn (giả sử là 10 byte), vẫn còn nhiều việc hơn để so sánh 2 băm 10 byte so với 2 int 4 byte.
Joel Coehoorn

KHÔNG BAO GIỜ sử dụng khóa dài (rộng) để tham gia ... Nhưng nếu đó là đại diện tốt nhất cho những gì là duy nhất cho các hàng trong bảng, thì tốt hơn là có một khóa duy nhất (hoặc chỉ mục - là cùng một thứ) trên bảng sử dụng các giá trị tự nhiên. Chìa khóa không có để tham gia, bạn có thể tham gia vào bất cứ điều gì trái tim bạn mong muốn. Các phím có để đảm bảo tính nhất quán của dữ liệu.
Charles Bretana

6

Đối với Khóa chính, bất kỳ nội dung nào làm cho một hàng duy nhất phải được xác định là khóa chính.

Đối với tham chiếu là khóa ngoại, sử dụng số nguyên tăng tự động làm đại diện thay thế là một ý tưởng hay vì hai lý do chính.
- Đầu tiên, thường có ít chi phí phát sinh trong việc tham gia thường xuyên.
- Thứ hai, nếu bạn cần cập nhật bảng chứa varchar duy nhất thì bản cập nhật phải xếp tầng xuống tất cả các bảng con và cập nhật tất cả chúng cũng như các chỉ mục, trong khi với int thay thế, nó chỉ phải cập nhật bảng tổng thể và nó là chỉ mục.

Hạn chế của việc sử dụng người thay thế là bạn có thể cho phép thay đổi ý nghĩa của người thay thế:

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

Tất cả phụ thuộc vào những gì bạn thực sự cần phải lo lắng trong cấu trúc của bạn và những gì có nghĩa nhất.


3

Các trường hợp phổ biến khi người thay thế bị AUTO_INCREMENTtổn thương:

Một mẫu lược đồ phổ biến là ánh xạ nhiều-nhiều :

CREATE TABLE map (
    id ... AUTO_INCREMENT,
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(id),
    UNIQUE(foo_id, bar_id),
    INDEX(bar_id) );

Hiệu suất của mẫu này tốt hơn nhiều, đặc biệt là khi sử dụng InnoDB:

CREATE TABLE map (
    # No surrogate
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(foo_id, bar_id),
    INDEX      (bar_id, foo_id) );

Tại sao?

  • Khóa phụ InnoDB cần tra cứu thêm; bằng cách di chuyển cặp vào PK, điều đó tránh được một hướng.
  • Chỉ số phụ là "bao phủ", vì vậy nó không cần tra cứu thêm.
  • Bảng này nhỏ hơn vì loại bỏ idvà một chỉ mục.

Một trường hợp khác ( quốc gia ):

country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii

Tất cả quá thường xuyên, người mới bình thường hóa country_code thành 4 byte INTthay vì sử dụng chuỗi 2 byte 'tự nhiên', gần như không thay đổi. Nhanh hơn, nhỏ hơn, ít THAM GIA hơn, dễ đọc hơn.


2

Tại HauteLook, chúng tôi đã thay đổi nhiều bảng để sử dụng các phím tự nhiên. Chúng tôi đã trải nghiệm sự gia tăng hiệu suất trong thế giới thực. Như bạn đã đề cập, nhiều truy vấn của chúng tôi hiện sử dụng ít tham gia hơn, điều này làm cho các truy vấn trở nên hiệu quả hơn. Chúng tôi thậm chí sẽ sử dụng khóa chính tổng hợp nếu nó có ý nghĩa. Điều đó đang được nói, một số bảng chỉ dễ làm việc hơn nếu chúng có khóa thay thế.

Ngoài ra, nếu bạn cho phép mọi người viết giao diện vào cơ sở dữ liệu của mình, khóa thay thế có thể hữu ích. Bên thứ 3 có thể dựa vào thực tế là khóa thay thế sẽ chỉ thay đổi trong những trường hợp rất hiếm.


2

Tôi phải đối mặt với tình trạng khó xử tương tự. Tôi đã tạo một DW (lược đồ chòm sao) với 3 bảng thực tế, Tai nạn đường bộ, Phương tiện gặp tai nạn và Thương vong trong Tai nạn. Dữ liệu bao gồm tất cả các vụ tai nạn được ghi nhận tại Vương quốc Anh từ năm 1979 đến năm 2012 và bảng 60 chiều. Tất cả cùng nhau, khoảng 20 triệu hồ sơ.

Các mối quan hệ bảng thực tế:

+----------+          +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1      * +----v----+
     1|                    |1
      |    +----------+    |
      +---<| Casualty |>---+
         * +----------+ *

RDMS: MySQL 5.6

Về cơ bản, chỉ số Tai nạn là một varchar (số và chữ), có 15 chữ số. Tôi đã cố gắng không có chìa khóa thay thế, một khi các chỉ số tai nạn sẽ không bao giờ thay đổi. Trong máy tính i7 (8 lõi), DW trở nên quá chậm để truy vấn sau 12 triệu bản ghi tải tùy thuộc vào kích thước. Sau rất nhiều lần làm việc lại và thêm các khóa thay thế bigint, tôi đã tăng hiệu suất tốc độ trung bình 20%. Tuy nhiên để đạt được hiệu suất thấp, nhưng thử hợp lệ. Tôi đang làm việc trong điều chỉnh và phân cụm MySQL.


1
Âm thanh như bạn cần phải nhìn vào phân vùng.
jcoffland

2

Câu hỏi là về MySQL vì vậy tôi nói có một sự khác biệt đáng kể. Nếu đó là về Oracle (nơi lưu trữ các số dưới dạng chuỗi - vâng, tôi không thể tin vào lúc đầu) thì không có nhiều khác biệt.

Lưu trữ trong bảng không phải là vấn đề nhưng cập nhật và đề cập đến chỉ mục là. Các truy vấn liên quan đến việc tìm kiếm một bản ghi dựa trên khóa chính của nó là thường xuyên - bạn muốn chúng xảy ra nhanh nhất có thể vì chúng xảy ra quá thường xuyên.

Điều này là một CPU xử lý các số nguyên 4 byte và 8 byte một cách tự nhiên, bằng silicon . Thật sự rất nhanh để nó so sánh hai số nguyên - nó xảy ra trong một hoặc hai chu kỳ đồng hồ.

Bây giờ hãy nhìn vào một chuỗi - nó được tạo thành từ rất nhiều ký tự (nhiều hơn một byte cho mỗi ký tự ngày nay). So sánh hai chuỗi ưu tiên không thể được thực hiện trong một hoặc hai chu kỳ. Thay vào đó, các ký tự của chuỗi phải được lặp lại cho đến khi tìm thấy sự khác biệt. Tôi chắc chắn có những thủ thuật để làm cho nó nhanh hơn trong một số cơ sở dữ liệu nhưng điều đó không liên quan ở đây vì một phép so sánh int được thực hiện một cách tự nhiên và nhanh như chớp trong silicon bởi CPU.

Quy tắc chung của tôi - mọi khóa chính phải là INT tự động tăng cường, đặc biệt là trong các ứng dụng OO sử dụng ORM (Hibernate, Datanucleus, bất cứ điều gì) trong đó có rất nhiều mối quan hệ giữa các đối tượng - chúng thường sẽ luôn được triển khai như một FK đơn giản và khả năng cho DB để giải quyết những vấn đề nhanh đó rất quan trọng đối với khả năng phản hồi của ứng dụng.


0

Không chắc chắn về ý nghĩa hiệu suất, nhưng có vẻ như một sự thỏa hiệp có thể, ít nhất là trong quá trình phát triển, sẽ bao gồm cả khóa "thay thế số nguyên" tự động, cũng như khóa "tự nhiên" duy nhất, dự định của bạn. Điều này sẽ cung cấp cho bạn cơ hội để đánh giá hiệu suất, cũng như các vấn đề khác có thể xảy ra, bao gồm cả khả năng thay đổi của các phím tự nhiên.


0

Như thường lệ, không có câu trả lời chăn. 'Nó phụ thuộc!' và tôi không phải là người lãnh đạm Sự hiểu biết của tôi về câu hỏi ban đầu là về các khóa trên các bảng nhỏ - như Quốc gia (mã số nguyên hoặc mã char / varchar) là một khóa ngoại đối với một bảng có khả năng lớn như bảng địa chỉ / liên hệ.

Có hai kịch bản ở đây khi bạn muốn lấy lại dữ liệu từ DB. Đầu tiên là một loại truy vấn danh sách / tìm kiếm nơi bạn muốn liệt kê tất cả các liên hệ với mã hoặc tên quốc gia và quốc gia (id sẽ không giúp đỡ và do đó sẽ cần tra cứu). Cái còn lại là một kịch bản get trên khóa chính hiển thị một bản ghi liên hệ duy nhất trong đó tên của tiểu bang, quốc gia cần được hiển thị.

Đối với lần nhận sau, có lẽ không có vấn đề gì về FK dựa trên vì chúng ta tập hợp các bảng cho một bản ghi hoặc một vài bản ghi và trên các lần đọc chính. Kịch bản trước đây (tìm kiếm hoặc danh sách) có thể bị ảnh hưởng bởi sự lựa chọn của chúng tôi. Vì bắt buộc phải hiển thị quốc gia (ít nhất là mã có thể nhận biết và thậm chí chính tìm kiếm đó bao gồm mã quốc gia), nên không phải tham gia bảng khác thông qua khóa thay thế có thể xảy ra (tôi chỉ thận trọng ở đây vì tôi chưa thực sự kiểm tra điều này, nhưng dường như rất có thể) cải thiện hiệu suất; mặc dù thực tế là nó chắc chắn sẽ giúp tìm kiếm.

Vì các mã có kích thước nhỏ - thường không quá 3 ký tự cho quốc gia và tiểu bang, nên có thể sử dụng các khóa tự nhiên làm khóa ngoại trong kịch bản này.

Kịch bản khác trong đó các khóa phụ thuộc vào các giá trị varchar dài hơn và có lẽ trên các bảng lớn hơn; chìa khóa thay thế có lẽ có lợi thế.


0

Cho phép tôi nói có, chắc chắn có sự khác biệt, có tính đến phạm vi hoạt động (Định nghĩa ngoài hộp):

1- Sử dụng thay thế int nhanh hơn trong ứng dụng vì bạn không cần sử dụng ToUpper (), ToLower (), ToUpperInvarient () hoặc ToLowerInvarient () trong mã của bạn hoặc trong truy vấn của bạn và 4 hàm này có các điểm chuẩn hiệu suất khác nhau. Xem quy tắc hiệu suất của Microsoft về điều này. (hiệu suất của ứng dụng)

2- Sử dụng thay thế int đảm bảo không thay đổi khóa theo thời gian. Ngay cả mã quốc gia cũng có thể thay đổi, hãy xem Wikipedia cách mã ISO thay đổi theo thời gian. Điều đó sẽ mất rất nhiều thời gian để thay đổi khóa chính cho các cây con. (hiệu suất bảo trì dữ liệu)

3- Dường như có vấn đề với các giải pháp ORM, chẳng hạn như NHibernate khi PK / FK không phải là int. (hiệu suất của nhà phát triển)

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.