ทำไม MySQL ไม่มีแฮชดัชนีใน MyISAM หรือ InnoDB


35

ฉันมีแอพพลิเคชั่นที่จะเลือกใช้ความเท่าเทียมกันเท่านั้นและฉันคิดว่าฉันควรใช้ดัชนีแฮชเหนือดัชนี btree MyISAM หรือ InnoDB ไม่รองรับดัชนีแฮชของฉัน เกิดอะไรขึ้นกับสิ่งนั้น


2
mysql ยังไม่สนับสนุนการจัดทำดัชนีฟังก์ชั่นที่ใช้ดัชนีบิตแมป ฯลฯ ฯลฯ เพียงเพราะมันเป็น MySQL ;-)

1
ฉันเพิ่งคิดว่าดัชนีแฮชเป็นเช่นนั้น ... พื้นฐาน ... ฉันคิดว่ามีเหตุผลที่เกี่ยวข้องกับการใช้งานเฉพาะ

1
@Alex: ฉันเดิมพันด้วยเหตุผลว่าเป็น "ความเกียจคร้าน" และ "ระบบราชการ" แต่ให้รอคำตอบ))


ฉันได้เพิ่มอัลกอริธึมแฮชที่ดีจากหนังสือประสิทธิภาพสูง MySQL ไปยังท้ายคำตอบของฉัน
RolandoMySQLDBA

คำตอบ:


16

ฐานข้อมูลจำนวนมากไม่สนับสนุนดัชนีตามกัญชาที่ทั้งหมด

เพื่อให้ตารางแฮชมีประสิทธิภาพคุณจำเป็นต้องทราบจำนวนแถวที่น่าจะมีอยู่มิฉะนั้นตารางแฮชพื้นฐานจะใหญ่เกินไป (รายการที่ว่างเปล่าจำนวนมากการสูญเสียพื้นที่และดิสก์ IO) หรือมีขนาดเล็กเกินไป ทางอ้อมมักใช้ (อาจมีหลายระดับทางอ้อมหรือแย่กว่านั้นหากการนำ hash มาใช้เป็นระดับเดียวคุณสามารถทำการค้นหาแบบเป็นเส้นตรงกับจำนวนเรคคอร์ดที่พอใช้) ซึ่งสิ่งต่าง ๆ อาจไม่มีประสิทธิภาพมากกว่าต้นไม้ จัดทำดัชนีต่อไป

ดังนั้นโดยทั่วไปจะมีประโยชน์ (เช่นมักจะดีกว่าทางเลือก) ดัชนีจำเป็นต้องสร้างใหม่เป็นครั้งคราวเมื่อข้อมูลเติบโต (และลดขนาดลง) ซึ่งสามารถเพิ่มค่าใช้จ่ายที่ไม่สม่ำเสมอเป็นระยะ นี้มักจะดีกับตารางตามหน่วยความจำเนื่องจากการสร้างอาจจะค่อนข้างเร็ว (เนื่องจากข้อมูลมักจะอยู่ใน RAM และไม่น่าจะมีขนาดใหญ่ในทุกกรณี) แต่การสร้างดัชนีขนาดใหญ่บนดิสก์ใหม่ การทำงานหนักมาก (และ IIRC mySQL ไม่รองรับการสร้างดัชนีใหม่ดังนั้นจึงมีการล็อคตารางระหว่างการดำเนินการ)

ดังนั้นดัชนีแฮชจะถูกใช้ในตารางหน่วยความจำเนื่องจากโดยทั่วไปมักจะมีประสิทธิภาพที่ดีกว่า แต่ตารางที่ใช้ดิสก์ไม่สนับสนุนเนื่องจากอาจเป็นอันตรายต่อประสิทธิภาพไม่ใช่โบนัส ไม่มีอะไรที่จะจัดทำดัชนีกัญชาหยุดการทำใช้ได้สำหรับตารางตามดิสก์ของหลักสูตรคือไม่มีข้อสงสัยฐานข้อมูลบางอย่างทำสนับสนุนคุณลักษณะ แต่สันนิษฐานว่าพวกเขาจะไม่ดำเนินการใน ISAM / ตาราง InnoDB เป็นผู้ดูแลไม่ได้พิจารณามูลค่าคุณลักษณะเพิ่ม (ขณะที่ รหัสพิเศษสำหรับการเขียนและบำรุงรักษาไม่คุ้มค่ากับผลประโยชน์ในบางสถานการณ์ที่ทำให้เกิดความแตกต่างอย่างมีนัยสำคัญ) บางทีถ้าคุณไม่เห็นด้วยอย่างยิ่งคุณสามารถพูดคุยกับพวกเขาและทำให้เป็นกรณีที่ดีสำหรับการใช้งานคุณลักษณะ

หากคุณกำลังจัดทำดัชนีสตริงขนาดใหญ่ดังนั้นการใช้ดัชนีแฮชหลอกของคุณเอง (โดยการจัดเก็บแฮชของค่ารวมถึงค่าจริงและการจัดทำดัชนีที่มีคอลัมน์) อาจใช้งานได้ แต่จะมีประสิทธิภาพมากกว่าสำหรับสตริงขนาดใหญ่เท่านั้น การคำนวณค่าแฮชและค้นหาดัชนีต้นไม้โดยค่านี้มักจะเร็วกว่าจากนั้นเพียงแค่ค้นหาดัชนีต้นไม้โดยใช้ค่าที่ใหญ่กว่าสำหรับการเปรียบเทียบและหน่วยเก็บข้อมูลพิเศษที่ใช้จะไม่สำคัญ) จึงทำการวิเคราะห์ประสิทธิภาพก่อนดำเนินการ ในการผลิต


มีวิธีใดบ้างที่อนุญาตให้ทำการแฮชใหม่ (สร้างใหม่) แบบเคียงข้างกันโดยไม่ล็อกทั้งตาราง?
Pacerier

@Pierier: ไม่ใช่ที่ฉันรู้ด้วย MySQL (แม้ว่าพวกเขาจะได้เพิ่มคุณสมบัติตั้งแต่ฉันใช้มันครั้งล่าสุดดังนั้นตรวจสอบเอกสาร) แม้ในกรณีที่ DBMS รองรับการสร้าง / สร้างดัชนีออนไลน์นั้นไม่ใช่ตัวเลือกเริ่มต้น สิ่งที่ได้รับการล็อคจะแตกต่างกันไป: บางคนจะถือล็อคการเขียนบนโต๊ะเพื่อทำธุรกรรมอื่น ๆ จะไม่ล่าช้าถ้าพวกเขากำลังอ่านเพียงอย่างเดียว DMBSs บางคนจะล็อคตารางเต็ม หากคุณต้องการสร้างใหม่ออนไลน์ให้ตรวจสอบเอกสารแต่ละ DBMS ก่อนที่จะเลือกใช้
David Spillett

โดยปกติการสร้างใหม่จำเป็นเฉพาะเมื่อความยาวข้อมูลเพิ่มขึ้นเป็นสองเท่า พวกเขาต้องกังวลเกี่ยวกับความยาวของข้อมูลที่เพิ่มขึ้นเป็นสองเท่าทุกนาทีหรือไม่? (โดยปกติจะเกิดขึ้นน้อยมากเมื่อฐานข้อมูลมีขนาดใหญ่พอสำหรับเรื่องนี้)
SOFe

6

ในบันทึกที่เกี่ยวข้องคุณอาจพบการสนทนาเกี่ยวกับประเภทดัชนีจากเอกสาร PostgreSQL ที่น่าสนใจ มันไม่ได้อยู่ในเอกสารรุ่นล่าสุดอีกต่อไป (เนื่องจากการปรับแต่งตามมาฉันเอามันไป) แต่การซื้ออาจจะคล้ายกับ MySQL (และเหตุผลที่ดัชนีแฮชใช้สำหรับตารางฮีปเท่านั้น):

http://www.postgresql.org/docs/8.1/static/indexes-types.html

หมายเหตุ: การทดสอบได้แสดงดัชนีแฮชของ PostgreSQL เพื่อให้ทำงานได้ไม่ดีกว่าดัชนี B-tree และขนาดดัชนีและเวลาสร้างสำหรับดัชนีแฮชยิ่งแย่ลงมาก นอกจากนี้การดำเนินการดัชนีแฮชไม่ได้ถูกบันทึกใน WAL ในปัจจุบันดังนั้นดัชนีแฮชอาจต้องสร้างใหม่ด้วย REINDEX หลังจากฐานข้อมูลขัดข้อง ด้วยเหตุผลเหล่านี้ทำให้การใช้ดัชนีแฮชไม่ได้รับการสนับสนุนในขณะนี้ ในทำนองเดียวกันดัชนี R-tree ดูเหมือนจะไม่มีข้อได้เปรียบด้านประสิทธิภาพใด ๆ เมื่อเทียบกับการดำเนินการที่เทียบเท่าของดัชนี GiST เช่นเดียวกับดัชนีแฮชพวกเขาจะไม่ได้รับการบันทึก WAL และอาจต้องทำการทำดัชนีใหม่หลังจากฐานข้อมูลขัดข้อง ในขณะที่ปัญหาที่เกิดขึ้นกับดัชนีแฮชอาจได้รับการแก้ไขในที่สุดก็เป็นไปได้ว่าดัชนี R-tree จะถูกยกเลิกในอนาคต ผู้ใช้ควรโยกย้ายแอปพลิเคชันที่ใช้ดัชนี R-tree ไปยังดัชนี GiST

อีกครั้งเป็นรุ่นเฉพาะของ PostgreSQL แต่ควรบอกเป็นนัยว่าประเภทดัชนี "ธรรมชาติ" ไม่จำเป็นต้องให้ประสิทธิภาพที่ดีที่สุด


5

นี่คือสิ่งที่น่าสนใจ:

ตามหนังสือคู่มือการศึกษาการรับรอง MySQL 5.0 , หน้า 433, มาตรา 29.5.1

เอ็นจิ้น MEMORY ใช้ HASH โดยอัลกอริทึมการทำดัชนีเริ่มต้น

สำหรับหัวเราะฉันพยายามสร้างตาราง InnoDB และตาราง MyISAM ด้วยคีย์หลักโดยใช้ HASH ใน 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 ไม่ได้บ่น

UPDATE

ข่าวร้าย !!! ฉันใช้ SHOW INDEXES จาก มันบอกว่าดัชนีคือ BTREE

สร้างดัชนีไวยากรณ์ MySQL หน้าระบุว่ามีเพียงหน่วยความจำและเครื่องมือการเก็บรักษา NDB สามารถรองรับกัญชาดัชนี

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)

บางคนแนะนำให้ติดตามแนวคิดในหน้า 102-105 ของหนังสือ " MySQL ประสิทธิภาพสูง: การเพิ่มประสิทธิภาพการสำรองข้อมูลการจำลองแบบและอื่น ๆ " เพื่อจำลองอัลกอริทึมแฮช

หน้า 105 มีอัลกอริทึมที่รวดเร็วและสกปรกที่ฉันชอบ:

SELECT CONV(RIGHT(MD5('whatever value you want'),16),16,10) AS HASH64;

สร้างคอลัมน์สำหรับสิ่งนี้ในตารางใด ๆ และสร้างดัชนีค่านี้

ให้มันลอง !!!


5
ก่อนที่จะใช้เทคนิคการปลอมดัชนีแฮชในการผลิตให้ทำการวิเคราะห์ประสิทธิภาพก่อน สำหรับสตริงขนาดใหญ่มันสามารถสร้างความแตกต่างใหญ่ แต่คุณท้ายการนำทางดัชนีต้นไม้ในตอนท้ายและคุณมีการเปรียบเทียบพิเศษที่ต้องทำเพื่อค้นหาแถวที่ถูกต้องจากที่พบตรงกับแฮชดังนั้นสำหรับค่าขนาดเล็กคำนวณค่าแฮชและ การจัดเก็บข้อมูลเหล่านั้นไม่คุ้มค่า นี่ไม่ใช่ดัชนีแฮชจริง ๆ เลยคุณเพียงแค่ลดงานที่ทำบนต้นไม้ (เนื่องจากการเปรียบเทียบแต่ละรายการกำลังพิจารณาไบต์น้อยลงเช่นการเปรียบเทียบ 8 ไบต์ INT แทนที่จะเป็นสตริง x00 ไบต์)
David Spillett

@ David Spillett ในนี้ฉันต้องเห็นด้วยกับคุณโดยสิ้นเชิง กลยุทธ์การจัดทำดัชนีอื่น ๆ ยังแนะนำในหนังสือเล่มเดียวกันในบทที่ 11 "กลยุทธ์การจัดทำดัชนีเพื่อประสิทธิภาพสูง" เพื่อเป็นการเพิ่มคำตอบของฉันหนังสือเล่มนี้กล่าวถึงการใช้ดัชนีแบบกลุ่มซึ่งเก็บแถวและดัชนี BTree ในโครงสร้างเดียวกัน นี่อาจเป็นการเร่งความเร็วของงานที่คุณพูดถึง น่าเสียดายที่ห่วงที่คุณต้องกระโดดผ่านสิ่งที่คุณเพิ่งพูดถึงนั้นค่อนข้างหลีกเลี่ยงไม่ได้ +1 จากฉันในความคิดเห็นของคุณอย่างไรก็ตามคุณ !!! ที่จริงแล้ว +1 สำหรับคำตอบของคุณเช่นกัน
RolandoMySQLDBA

@RolandoMySQLDBA คุณสามารถอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับการเป็นส่วนหนึ่งใน "คร่ำเครียดที่กำหนดเอง" วรรคสุดท้ายดูเหมือนจะไม่ให้เบาะแสมาก ...
Pacerier

2

BTree นั้นไม่ช้ากว่า Hash มากนักสำหรับการค้นหาแถวเดียว เนื่องจาก BTree มีข้อความค้นหาที่หลากหลายและมีประสิทธิภาพมาก

MySQL ทำงานได้ดีมากในการแคชบล็อก BTree ดังนั้นแบบสอบถามที่ใช้ BTree จึงไม่ค่อยต้องทำ I / O ซึ่งเป็นผู้ใช้เวลามากที่สุดในแบบสอบถามใด ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.