Tôi có một ứng dụng sẽ chỉ chọn trên đẳng thức và tôi nghĩ rằng tôi nên sử dụng chỉ số băm trên chỉ mục btree. Điều này làm tôi mất tinh thần, các chỉ số băm không được hỗ trợ trên MyISAM hoặc InnoDB. Có chuyện gì thế?
Tôi có một ứng dụng sẽ chỉ chọn trên đẳng thức và tôi nghĩ rằng tôi nên sử dụng chỉ số băm trên chỉ mục btree. Điều này làm tôi mất tinh thần, các chỉ số băm không được hỗ trợ trên MyISAM hoặc InnoDB. Có chuyện gì thế?
Câu trả lời:
Nhiều cơ sở dữ liệu không hỗ trợ chỉ số dựa băm ở tất cả .
Để bảng băm hoạt động hiệu quả, bạn cần biết số lượng hàng có khả năng xuất hiện nếu không bảng băm cơ sở sẽ quá lớn (nhiều mục trống, lãng phí không gian và có khả năng IO đĩa) hoặc quá nhỏ Sự gián tiếp thường được sử dụng (có thể là nhiều cấp độ gián tiếp, hoặc thậm chí tệ hơn nếu triển khai hàm băm là một cấp độ mà bạn có thể thực hiện tìm kiếm tuyến tính trên một số lượng hồ sơ hợp lý) tại đó mọi thứ có thể không hiệu quả hơn sau đó dựa trên cây chỉ số nào.
Vì vậy, nói chung là hữu ích (thường là tốt hơn so với giải pháp thay thế), chỉ số thỉnh thoảng cần được xây dựng lại khi dữ liệu tăng (và thu hẹp) có thể thêm một chi phí không liên tục đáng kể. Điều này thường ổn với các bảng dựa trên bộ nhớ vì việc xây dựng lại có thể sẽ khá nhanh (vì dữ liệu luôn nằm trong RAM và không có khả năng lớn trong mọi trường hợp), nhưng việc xây dựng lại một chỉ mục lớn trên đĩa là một Hoạt động rất nặng (và IIRC myQuery không hỗ trợ xây dựng lại chỉ mục trực tiếp để giữ khóa bảng trong quá trình hoạt động).
Do đó, các chỉ mục băm được sử dụng trong các bảng bộ nhớ vì chúng thường có hiệu suất tốt hơn, nhưng các bảng dựa trên đĩa không hỗ trợ chúng vì chúng có thể gây bất lợi cho hiệu suất không phải là phần thưởng. Không có gì để chỉ số băm dừng được làm sẵn có cho các bảng dựa đĩa dĩ nhiên là, không có nghi ngờ một số cơ sở dữ liệu làm hỗ trợ tính năng này, nhưng có lẽ họ không được thực hiện trong ISAM / bảng InnoDB như các nhà bảo trì không xem xét các giá trị tính năng bổ sung (tùy theo từng mã bổ sung để viết và duy trì không có giá trị lợi ích trong một vài trường hợp mà nó tạo ra sự khác biệt đáng kể). Có lẽ nếu bạn hoàn toàn không đồng ý, bạn có thể nói chuyện với họ và đưa ra một trường hợp tốt để thực hiện tính năng này.
Nếu bạn đang lập chỉ mục các chuỗi lớn thì việc triển khai chỉ mục băm giả của riêng bạn (bằng cách lưu trữ giá trị băm của giá trị cũng như giá trị thực và lập chỉ mục có cột) có thể hoạt động, nhưng điều này chỉ hiệu quả hơn đối với các chuỗi lớn (trong đó tính toán giá trị băm và tìm kiếm chỉ mục cây theo giá trị này luôn có khả năng nhanh hơn sau đó chỉ cần tìm kiếm một chỉ mục cây bằng cách sử dụng các giá trị lớn hơn để so sánh và lưu trữ bổ sung được sử dụng sẽ không đáng kể) vì vậy hãy phân tích hiệu suất trước khi thực hiện Điều này trong sản xuất.
Trên một lưu ý liên quan, bạn có thể thấy cuộc thảo luận về các loại chỉ mục từ các tài liệu PostgreSQL thú vị. Nó không còn xuất hiện trong các phiên bản gần đây của tài liệu (do tối ưu hóa tiếp theo, tôi lấy nó), nhưng việc mua lại có thể giống với MySQL (và lý do tại sao các chỉ mục băm chỉ được sử dụng cho các bảng heap):
http://www.postgresql.org/docs/8.1/static/indexes-types.html
Lưu ý: Kiểm tra đã cho thấy các chỉ mục băm của PostgreSQL hoạt động không tốt hơn các chỉ mục B-tree và kích thước chỉ mục và thời gian xây dựng cho các chỉ mục băm tồi tệ hơn nhiều. Hơn nữa, các hoạt động chỉ mục băm hiện không được ghi nhật ký WAL, vì vậy các chỉ mục băm có thể cần phải được xây dựng lại với REINDEX sau khi sự cố cơ sở dữ liệu. Vì những lý do này, việc sử dụng chỉ số băm hiện không được khuyến khích. Tương tự, các chỉ mục của cây R dường như không có bất kỳ lợi thế về hiệu suất so với các hoạt động tương đương của các chỉ mục GiST. Giống như các chỉ mục băm, chúng không được ghi nhật ký WAL và có thể cần reindexing sau khi sự cố cơ sở dữ liệu. Mặc dù các vấn đề với chỉ mục băm cuối cùng có thể được khắc phục, có khả năng loại chỉ mục cây R sẽ bị loại bỏ trong phiên bản tương lai. Người dùng được khuyến khích di chuyển các ứng dụng sử dụng chỉ mục R-tree sang chỉ mục GiST.
Một lần nữa, nó (phiên bản lỗi thời) cụ thể của PostgreSQL, nhưng cần gợi ý rằng loại chỉ mục "tự nhiên" sẽ không nhất thiết mang lại hiệu suất tối ưu.
Đây là một điều thú vị:
Theo cuốn sách Hướng dẫn nghiên cứu chứng chỉ MySQL 5.0 , Trang 433, Mục 29.5.1
Công cụ MEMORY sử dụng HASH theo thuật toán lập chỉ mục mặc định.
Để cười, tôi đã cố gắng tạo bảng InnoDB và bảng MyISAM với khóa chính bằng HASH trong MySQL 5.5.12
mysql> use test
Database changed
mysql> create table rolando (num int not null, primary key (num) using hash);
Query OK, 0 rows affected (0.11 sec)
mysql> show create table rolando\G
*************************** 1. row ***************************
Table: rolando
Create Table: CREATE TABLE `rolando` (
`num` int(11) NOT NULL,
PRIMARY KEY (`num`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> create table rolando2 (num int not null, primary key (num) using hash) engine=MyISAM;
Query OK, 0 rows affected (0.05 sec)
mysql> show create table rolando2\G
*************************** 1. row ***************************
Table: rolando2
Create Table: CREATE TABLE `rolando2` (
`num` int(11) NOT NULL,
PRIMARY KEY (`num`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
MySQL đã không phàn nàn.
CẬP NHẬT
Tin xấu !!! Tôi đã sử dụng CHỈ SỐ SHOW TỪ. Nó nói chỉ số là BTREE.
Các CREATE INDEX cú pháp MySQL Trang khẳng định rằng chỉ có bộ nhớ và công cụ lưu trữ NDB có thể thích ứng với INDEX HASH.
mysql> show indexes from rolando;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rolando | 0 | PRIMARY | 1 | num | A | 0 | NULL | NULL | | BTREE | | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
mysql> show indexes from rolando2;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rolando2 | 0 | PRIMARY | 1 | num | A | 0 | NULL | NULL | | BTREE | | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
mysql> create table rolando3 (num int not null, primary key (num)) ENGINE=MEMORY;
Query OK, 0 rows affected (0.03 sec)
mysql> show create table rolando3\G
*************************** 1. row ***************************
Table: rolando3
Create Table: CREATE TABLE `rolando3` (
`num` int(11) NOT NULL,
PRIMARY KEY (`num`)
) ENGINE=MEMORY DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> show indexes from rolando3;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rolando3 | 0 | PRIMARY | 1 | num | NULL | 0 | NULL | NULL | | HASH | | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
Một số người đề xuất theo ý tưởng trong Trang 102-105 của cuốn sách " MySQL hiệu suất cao: Tối ưu hóa, sao lưu, sao chép và hơn thế nữa " để mô phỏng thuật toán băm.
Trang 105 có thuật toán nhanh và bẩn này mà tôi thích:
SELECT CONV(RIGHT(MD5('whatever value you want'),16),16,10) AS HASH64;
Tạo một cột cho điều này trong bất kỳ bảng nào và lập chỉ mục giá trị này.
Hãy thử một lần !!!
BTree không chậm hơn nhiều so với Hash cho tra cứu một hàng. Vì BTree cung cấp các truy vấn phạm vi rất hiệu quả, tại sao phải bận tâm với bất cứ điều gì khác ngoài BTree.
MySQL thực hiện rất tốt việc lưu trữ các khối BTree, do đó, một truy vấn dựa trên BTree hiếm khi phải thực hiện I / O, đây là công cụ tiêu dùng lớn nhất trong mọi truy vấn.