INDEX có thể có trên trường VARCHAR trong MySql


40

Tôi đang làm việc trong cơ sở dữ liệu MySql , với một bảng như thế này:

+--------------+
|  table_name  |
+--------------+
|    myField   |
+--------------+

... Và tôi cần thực hiện nhiều truy vấn như thế này (có 5-10 chuỗi trong danh sách) :

SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)

Sẽ có khoảng 24.000.000 hàng duy nhất

1) Tôi nên sử dụng một FULLTEXThoặc và INDEXchìa khóa cho tôi VARCHAR(150)?
2) Nếu tôi tăng ký tự từ 150 lên 220 hoặc 250 ... nó có tạo ra sự khác biệt lớn không? (Có cách nào để tính toán không?)
3) Như tôi đã nói, chúng sẽ là duy nhất, vì vậy myField phải là một KHÓA CHÍNH . Không phải là hiếm khi thêm KHÓA CHÍNH vào trường đã là VARCHAR INDEX / FULLTEXT?


bạn không cần phải sử dụng PRIMARY cho tính duy nhất. Đã có ĐỘC ĐÁO cho điều đó.
kommradHomer

Câu trả lời:


62

SUGGESTION # 1: Lập chỉ mục tiêu chuẩn

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    key (myfield)
);

Nếu bạn lập chỉ mục như thế này, bạn có thể tìm kiếm toàn bộ chuỗi hoặc thực hiện tìm kiếm THÍCH hướng trái

SUGGESTION # 2: Lập chỉ mục FULLTEXT

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    fulltext (myfield)
);

Bạn có thể sử dụng hiệu quả các tìm kiếm cho các từ khóa riêng lẻ cũng như toàn bộ cụm từ. Bạn sẽ cần xác định danh sách từ khóa tùy chỉnh vì MySQL sẽ không lập chỉ mục 543 từ .

Đây là những bài viết khác của tôi trong hai năm qua về các chỉ mục FULLTEXT

SUGGESTION # 3: Lập chỉ mục băm

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    hashmyfield char(32) not null,
    primary key (id),
    key (hashmyfield)
);

Nếu bạn đang tìm kiếm một giá trị cụ thể và các giá trị đó có thể dài hơn 32 ký tự, bạn có thể lưu trữ giá trị băm:

INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));

Bằng cách đó, bạn chỉ cần tìm kiếm các giá trị băm để lấy kết quả

SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');

Hãy thử một lần !!!


Tôi không đủ danh tiếng để bỏ phiếu cho câu trả lời của bạn nhưng tôi phải nói rằng đó là TUYỆT VỜI. Cảm ơn bạn đã giải thích và các ví dụ. Tôi nghĩ rằng lập chỉ mục băm là tốt nhất cho trường hợp của tôi, nó là một giải pháp tuyệt vời. Nhưng vẫn còn một câu hỏi: bạn nghĩ giới hạn của các hàng cho tìm kiếm nhanh trong bảng sẽ là gì? [sử dụng như KEY VARCHAR (32) cho các tìm kiếm]
Mark Tower

2
Tùy chọn băm ở đây vẫn là một văn bản và 32 byte cho 16 byte thực sự. Bạn có thể sử dụng sử dụng trường bigint với đối số (trái (md5 ('sao cũng được), 16), 16, -10). Không có số 16 byte nhưng bạn có thể tìm thấy một nửa số md5 đủ và sau đó chỉ có 8 byte trong chỉ mục
atxdba

1
Thật không tốt khi sử dụng MD5 hoặc SHA1 để tạo ra các chuỗi sẽ được lập chỉ mục. Phân phối chuỗi được tạo bởi các hàm băm như MD5 hoặc SHA1 là ngẫu nhiên trong một không gian rộng làm giảm hiệu quả của chỉ mục của bạn, điều này có thể làm chậm các câu lệnh INSERT và SELECT. Đây là bài viết giải thích về nó: code-epicenter.com/ từ
Mr.M

Tôi xin lỗi vì đây là một chủ đề cũ, nhưng câu hỏi của tôi liên quan trực tiếp đến vấn đề này nhưng tôi không thể nhận được câu trả lời rõ ràng cho nhu cầu của mình từ việc đọc qua các bài viết trên và các bài viết tương tự khác. Kịch bản của tôi là: Tôi đang phát triển một hệ thống chứng khoán rất thô sơ chỉ bao gồm một bảng duy nhất. Nó được truy cập bên ngoài thông qua API nên tất cả cấu hình được giữ ở nơi khác - đó là lý do tại sao chúng ta chỉ cần một bảng duy nhất. Hai cột mà tôi đang nghĩ về lập chỉ mục, sẽ có khoảng 200 mục duy nhất mỗi mục, có độ dài <20 ký tự. Tôi có nên xem xét thêm chỉ số?
Mike

Đây có phải là định hướng trái như tìm kiếm like 'a%'?
Kế toán م

18

MySQL cho phép bạn xác định chỉ mục tiền tố, có nghĩa là bạn xác định N ký tự đầu tiên từ chuỗi gốc sẽ được lập chỉ mục và mẹo là chọn một số N đủ dài để cung cấp độ chọn lọc tốt, nhưng đủ ngắn để tiết kiệm không gian. Tiền tố phải đủ dài để làm cho chỉ mục gần như hữu ích nếu bạn lập chỉ mục cho toàn bộ cột.

Trước khi chúng ta đi xa hơn hãy để chúng tôi xác định một số điều khoản quan trọng. Độ chọn lọc chỉ mục là tỷ lệ của tổng giá trị được lập chỉ mục riêng biệt và tổng số hàng . Đây là một ví dụ cho bảng thử nghiệm:

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

Nếu chúng ta chỉ lập chỉ mục ký tự đầu tiên (N = 1), thì bảng chỉ mục sẽ trông giống như bảng sau:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

Trong trường hợp này, độ chọn lọc chỉ số bằng IS = 1/3 = 0,33.

Bây giờ chúng ta hãy xem điều gì sẽ xảy ra nếu chúng ta tăng số lượng ký tự được lập chỉ mục lên hai (N = 2).

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

Trong kịch bản này IS = 2/3 = 0,66 có nghĩa là chúng tôi đã tăng độ chọn lọc chỉ mục, nhưng chúng tôi cũng đã tăng kích thước của chỉ mục. Thủ thuật là tìm số N tối thiểu sẽ dẫn đến độ chọn lọc chỉ số tối đa .

Có hai cách tiếp cận bạn có thể thực hiện tính toán cho bảng cơ sở dữ liệu của mình. Tôi sẽ thực hiện trình diễn trên bãi chứa cơ sở dữ liệu này .

Giả sử chúng tôi muốn thêm cột Last_name trong bảng nhân viên vào chỉ mục và chúng tôi muốn xác định số N nhỏ nhất sẽ tạo ra độ chọn lọc chỉ mục tốt nhất.

Đầu tiên chúng ta hãy xác định tên cuối cùng thường xuyên nhất:

select count(*) as cnt, last_name from employees group by employees.last_name order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

Như bạn có thể thấy, tên cuối cùng Baba là tên thường xuyên nhất. Bây giờ chúng ta sẽ tìm các tiền tố last_name xảy ra thường xuyên nhất , bắt đầu bằng các tiền tố năm chữ cái.

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

Có nhiều lần xuất hiện hơn của mọi tiền tố, có nghĩa là chúng ta phải tăng số N cho đến khi các giá trị gần giống như trong ví dụ trước.

Đây là kết quả cho N = 9

select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

Đây là kết quả cho N = 10.

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

Đây là kết quả rất tốt. Điều này có nghĩa là chúng ta có thể tạo chỉ mục trên cột last_name chỉ với 10 ký tự đầu tiên. Trong cột định nghĩa bảng, Last_name được định nghĩa là VARCHAR(16)và điều này có nghĩa là chúng tôi đã lưu 6 byte (hoặc nhiều hơn nếu có các ký tự UTF8 trong tên cuối cùng) cho mỗi mục nhập. Trong bảng này có 1637 giá trị riêng biệt nhân với 6 byte là khoảng 9KB và hãy tưởng tượng con số này sẽ tăng lên như thế nào nếu bảng của chúng tôi chứa hàng triệu hàng.

Bạn có thể đọc các cách tính số N khác trong bài viết của tôi Chỉ mục tiền tố trong MySQL .

Sử dụng các hàm MD5 và SHA1 để tạo các giá trị cần được lập chỉ mục cũng không phải là cách tiếp cận tốt . Tại sao? Đọc nó trong bài viết Cách chọn đúng loại dữ liệu cho khóa chính trong cơ sở dữ liệu MySQL


Đây là một câu trả lời rất dài cho một câu hỏi khác.
mustaccio

1
Bạn đang đùa tôi à
Mr.M

Bạn có thể giải thích những gì sai, hoặc những gì không thể được áp dụng cho câu hỏi?
Mr.M

2
Này MrD. Tôi thực sự thích câu trả lời của bạn. Tại sao ? Trong câu trả lời cũ của tôi, tôi đã nói trong SUGGESTION # 1 : If you index like this, you can either look for the whole string or do left-oriented LIKE searches. Tôi cũng đã nói trong SUGGESTION # 3 : If you are looking for one specific value and those values could be lengths well beyond 32 characters, you could store the hash value:. Câu trả lời của bạn thể hiện đầy đủ lý do tại sao người ta không nên sử dụng các khóa lớn và nên lập chỉ mục cho các ký tự ngoài cùng bên trái, điều này có thể tạo ra sự khác biệt về hiệu suất. Câu trả lời của bạn thuộc về đây. +1 cho câu trả lời của bạn và Chào mừng bạn đến với DBA StackExchange.
RolandoMySQLDBA
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.