web-dev-qa-db-ja.com

MySQLがMyISAMまたはInnoDBにハッシュインデックスを持たないのはなぜですか?

同等性のみを選択するアプリケーションがあり、btreeインデックスではなくハッシュインデックスを使用する必要があると思います。残念なことに、ハッシュインデックスはMyISAMまたはInnoDBではサポートされていません。どうしたの?

36
Alex

多くのデータベースはハッシュベースのインデックスをサポートしていませんまったく

ハッシュテーブルを効率的にするためには、存在する可能性のある行の数を知る必要があります。そうしないと、ベースハッシュテーブルが大きすぎる(多くの空のエントリ、スペースを浪費し、ディスクIOの可能性があります)か、または小さすぎます。多くの場合、間接指定が使用されます(おそらく複数レベルの間接指定、またはハッシュ実装が単一レベルの場合はかなりの数のレコードに対して線形検索を実行することになります)。とにかくインデックス。

そのため、一般的に役立つ(つまり、通常は代替よりも優れている)ために、データが増大(および縮小)するときにインデックスを再構築する必要があり、断続的なオーバーヘッドが大幅に増加する可能性があります。再構築はおそらくかなり高速になるため、これは通常メモリベースのテーブルで問題ありません(データは常にRAMにあり、どのような場合でも大規模になる可能性は低いため)。ただし、ディスク上の大きなインデックスの再構築は非常に重い操作です(IIRC mySQLはライブインデックスの再構築をサポートしていないため、操作中にテーブルロックを保持します)。

したがって、ハッシュインデックスは一般にパフォーマンスが高いため、メモリテーブルで使用されますが、ディスクベースのテーブルはそれらをサポートしていません。もちろん、ディスクベースのテーブルでハッシュインデックスを使用できるようにするものはありません。間違いなく一部のデータベースdoはこの機能をサポートしていますが、メンテナが考慮しないため、おそらくISAM/InnoDBテーブルに実装されていません追加する価値のある機能(作成して維持する追加のコードは、重要な違いをもたらすいくつかの状況ではメリットに値しないため)。おそらく、あなたが強く同意しない場合は、彼らと話をして、機能の実装について良い主張をすることができます。

大きな文字列にインデックスを付ける場合、独自の疑似ハッシュインデックスを実装することで(値のハッシュと実際の値を格納し、列を持つインデックスを作成することで)機能しますが、これは大きな文字列(ハッシュ値を計算し、この値でツリーインデックスを検索すると、比較のために大きい値を使用してツリーインデックスを検索するよりも常に高速になる可能性が高く、使用される追加のストレージはそれほど重要ではありません)実装前にパフォーマンス分析を行ってくださいこれは製造中です。

16
David Spillett

関連するメモとして、PostgreSQLのドキュメントのインデックスタイプに関する説明が興味深いかもしれません。最近のバージョンのドキュメントには存在しません(その後の最適化により、私はそれを採用しています)が、MySQLの場合も同様です(そして、ハッシュインデックスがヒープテーブルにのみ使用される理由):

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

注:テストの結果、PostgreSQLのハッシュインデックスはBツリーインデックスと同等以上のパフォーマンスを示し、ハッシュインデックスのインデックスサイズとビルド時間ははるかに悪くなっています。さらに、ハッシュインデックス操作は現在WALでログに記録されないため、データベースクラッシュ後にハッシュインデックスをREINDEXで再構築する必要がある場合があります。これらの理由により、ハッシュインデックスの使用は現在推奨されていません。同様に、Rツリーインデックスには、Gistインデックスの同等の操作と比較して、パフォーマンス上の利点がないようです。ハッシュインデックスのように、それらはWALログに記録されず、データベースがクラッシュした後にインデックスの再作成が必要になる場合があります。ハッシュインデックスの問題は最終的に修正される可能性がありますが、Rツリーインデックスタイプは将来のリリースで廃止される可能性があります。ユーザーは、Rツリーインデックスを使用するアプリケーションをGistインデックスに移行することをお勧めします。

繰り返しますが、これはPostgreSQL固有(廃止バージョン)ですが、「自然な」インデックスタイプが必ずしも最適なパフォーマンスをもたらすとは限らないことを示唆しているはずです。

6

ここに興味深いものがあります:

本によると MySQL 5.0 Certification Study Guide 、ページ433、セクション29.5.1

MEMORYエンジンは、デフォルトのインデックス作成アルゴリズムでHASHを使用します。

笑うために、MySQL 5.5.12のHASHを使用して、主キーを持つInnoDBテーブルとMyISAMテーブルを作成しようとしました

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は文句を言わなかった。

更新

悪いニュース !!! SHOW INDEXES FROMを使用しました。それはインデックスがBTREEであると言います。

CREATE INDEX構文MySQLページ は、MEMORYおよびNDBストレージエンジンのみがHASH INDEXに対応できることを示しています。

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
RolandoMySQLDBA

BTreeは、単一行ルックアップのハッシュよりもそれほど遅くありません。 BTreeは非常に効率的な範囲クエリを提供するので、BTree以外のものに悩む必要はありません。

MySQLはBTreeブロックをキャッシュするのに非常に優れています。そのため、BTreeベースのクエリがI/Oを実行する必要はほとんどありません。

2
Rick James