Chỉ mục: hiệu suất số nguyên so với chuỗi nếu số lượng nút là như nhau


26

Tôi đang phát triển một ứng dụng trong Ruby on Rails với cơ sở dữ liệu PostgreSQL (9.4). Đối với trường hợp sử dụng của tôi, các cột trong bảng sẽ được tra cứu rất thường xuyên, vì toàn bộ điểm của ứng dụng đang tìm kiếm các thuộc tính rất cụ thể trên một mô hình.

Tôi hiện đang quyết định có nên sử dụng một integerloại hoặc đơn giản là sử dụng một loại chuỗi điển hình (ví dụ character varying(255), đó là mặc định trong Rails ) cho các cột, như tôi không chắc chắn những gì khác biệt hiệu suất sẽ được trên các chỉ số.

Những cột này là enum . Chúng có kích thước cố định cho số lượng giá trị có thể có. Hầu hết độ dài enum không vượt quá 5, có nghĩa là chỉ số sẽ được cố định ít nhiều trong suốt vòng đời của ứng dụng ; do đó, các chỉ số nguyên và chuỗi sẽ giống hệt nhau về số lượng nút.

Tuy nhiên, chuỗi được lập chỉ mục có thể dài khoảng 20 ký tự, trong bộ nhớ gần bằng 5x so với số nguyên (nếu số nguyên là 4 byte và chuỗi là ASCII thuần ở mức 1 byte cho mỗi ký tự, thì số này giữ). Tôi không biết làm thế nào các công cụ cơ sở dữ liệu thực hiện tra cứu chỉ mục, nhưng nếu nó cần "quét" chuỗi cho đến khi nó khớp chính xác , thì về bản chất, điều đó có nghĩa là việc tra cứu chuỗi sẽ chậm hơn 5x so với tra cứu số nguyên; "quét" cho đến khi khớp với tra cứu số nguyên sẽ là 4 byte thay vì 20. Đây là những gì tôi đang tưởng tượng:

Giá trị tra cứu là (số nguyên) 4:

quét ............................ FOUND | nhận hồ sơ ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... |

Giá trị tra cứu là (chuỗi) "some_val" (8 byte):

quét ................................................. .................................... NỀN TẢNG | nhận hồ sơ ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... |

Tôi hy vọng điều đó có ý nghĩa. Về cơ bản, vì số nguyên chiếm ít không gian hơn, nên nó có thể được "khớp trên" nhanh hơn so với đối tác chuỗi của nó. Có lẽ đây là một dự đoán hoàn toàn sai, nhưng tôi không phải là chuyên gia, vì vậy đó là lý do tại sao tôi hỏi các bạn! Tôi cho rằng câu trả lời này tôi vừa tìm thấy dường như ủng hộ giả thuyết của tôi, nhưng tôi muốn chắc chắn.

Số lượng giá trị có thể có trong cột sẽ không thay đổi khi sử dụng một trong hai, do đó, chính chỉ mục sẽ không thay đổi (trừ khi tôi đã thêm một giá trị mới vào enum). Trong trường hợp này, liệu có sự khác biệt về hiệu suất trong việc sử dụng integerhoặc varchar(255), hoặc sử dụng một kiểu số nguyên có ý nghĩa hơn không?


Lý do tôi hỏi là enumloại bản đồ của Rails có các số nguyên cho các chuỗi chuỗi, nhưng chúng không có nghĩa là các cột đối diện với người dùng. Về cơ bản, bạn không thể xác minh rằng giá trị enum là hợp lệ, bởi vì giá trị không hợp lệ sẽ gây ra ArgumentErrortrước khi bất kỳ xác nhận nào có thể được chạy. Sử dụng một stringloại sẽ cho phép xác nhận, nhưng nếu có chi phí hiệu năng, tôi chỉ muốn khắc phục vấn đề xác nhận.

Câu trả lời:


32

Câu trả lời ngắn: integernhanh hơn varcharhoặc texttrong mọi khía cạnh. Không quan trọng lắm đối với các bảng nhỏ và / hoặc các phím ngắn. Sự khác biệt tăng theo chiều dài của các phím và số lượng hàng.

chuỗi ... dài 20 ký tự, trong bộ nhớ gần bằng 5x so với số nguyên (nếu số nguyên là 4 byte và chuỗi là ASCII thuần ở mức 1 byte cho mỗi ký tự, thì số này giữ)

Nói chính xác, các loại ký tự ( texthoặc varchar) chiếm chính xác 21 byte cho 20 ký tự ASCII trên đĩa và 23 byte trong RAM. Đánh giá chi tiết:

Cũng quan trọng: COLLATIONquy tắc có thể làm cho việc sắp xếp dữ liệu ký tự đắt hơn - không giống như các loại dữ liệu số:

Kích thước chỉ số có thể chịu trách nhiệm cho phần lớn sự khác biệt hiệu suất trong hầu hết các trường hợp. Hãy xem xét tổng phí trên mỗi bộ chỉ mục (về cơ bản giống như đối với bảng): 4 byte cho con trỏ mục và 24 byte cho tiêu đề bộ. Vì vậy, chỉ số tuple cho integersẽ lên tới 36 byte (bao gồm 4 byte đệm liên kết ) và varchar(20)với 20 ký tự ASCII, nó sẽ là 52 byte (cũng bao gồm đệm). Chi tiết:

Bỏ tất cả lý thuyết sang một bên: tốt nhất là chỉ kiểm tra:

Postgres 9.5 đã giới thiệu một tối ưu hóa để sắp xếp các chuỗi dữ liệu ký tự dài (từ khóa "các phím viết tắt" ). Nhưng một lỗi trong một số chức năng thư viện C trên Linux đã buộc dự án vô hiệu hóa tính năng cho các đối chiếu không phải C trong Postgres 9.5.2. Chi tiết trong ghi chú phát hành.

Tuy nhiên, nếu bạn thực sự sử dụng enumcác loại Postgres , hầu hết các cân nhắc này đều không liên quan, vì integerdù sao chúng cũng được thực hiện với các giá trị bên trong. Hướng dẫn sử dụng:

Một enumgiá trị chiếm bốn byte trên đĩa.

Ngoài ra: varchar(255)được sử dụng để hiểu các phiên bản đầu tiên của SQL Server, có thể sử dụng loại dữ liệu hiệu quả hơn bên trong đến giới hạn 255 ký tự. Nhưng hạn chế độ dài lẻ 255 ký tự không có tác động đặc biệt đến hiệu suất trong Postgres.


1
Không có tối ưu hóa ẩn trong SQL Server cho varchar(255)vs ví dụ varchar(260). Có thể đã có một điều như vậy với SQL Server 6.x nhưng điều này đã không đúng trong một thời gian dài.
a_horse_with_no_name

@a_horse_with_no_name: cảm ơn, tôi đã làm rõ tương ứng.
Erwin Brandstetter

Xin lỗi vì mất quá nhiều thời gian để chấp nhận điều này, tôi đã chậm phát triển dự án đó;)
Chris Cirefice

Câu trả lời này có còn hợp lệ cho Postgres 10 không?
Matty

1
@Matty: Vẫn còn hiệu lực. Và tôi cũng không thấy có gì thay đổi cho pg 11 cả.
Erwin Brandstetter
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.