MySqlのVARCHARフィールドで可能なINDEX


40

私は次のようなテーブルを使用して、MySqlデータベースで作業しています

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

...そして、私はこのような多くのクエリを作成する必要があります(リストに5〜10文字列)

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

約24.000.000の一意の行があります

1)FULLTEXTまたはにINDEXキーを使用する必要がありますVARCHAR(150)か?
2)文字を150から220または250に増やした場合、大きな違いが生じますか?(それを計算する方法はありますか?)
3)私が言ったように、それらはユニークになるので、myFieldPRIMARY KEYでなければなりません。すでにVARCHAR INDEX / FULLTEXTであるフィールドにPRIMARY KEYを追加することはまれではありませんか?


一意性のためにPRIMARYを使用する必要はありません。そのためにすでにユニークです。
kommradHomer

回答:


62

提案#1:標準のインデックス作成

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

このようなインデックスを作成する場合、文字列全体を検索するか、左向きのLIKE検索を実行できます。

提案#2:全文索引付け

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

フレーズ全体だけでなく、個々のキーワードの検索を効果的に使用できます。MySQLは543ワードを索引付けしないため、カスタムストップワードリストを定義する必要があります

FULLTEXTインデックスに関する過去2年間のその他の投稿を以下に示します。

提案#3:ハッシュインデックス作成

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

特定の値を1つ探していて、それらの値の長さが32文字をはるかに超える場合、ハッシュ値を保存できます。

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

そうすれば、ハッシュ値を検索して結果を取得するだけです

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

試してみる !!!


私はあなたの答えを投票するほどの評判はありませんが、それは素晴らしいと言わなければなりません。説明と例に感謝します。私の場合、ハッシュインデックスは最適だと思います。それは素晴らしい解決策です。しかし、まだ質問が1つあります。テーブル内の高速検索の行の制限はどうなると思いますか。[検索にVARCHAR(32)をキーとして使用]
マークタワー

2
ここでのハッシュオプションはテキストであり、実際には16バイトであるため32バイトです。conv(left(md5( 'whatever')、16)、16、-10)でbigintフィールドを使用できます。そこ16バイトの数値ではありませんが、あなたは、MD5十分の半分を見つけることができますし、それは、インデックスの唯一の8バイトだ
atxdba

1
MD5またはSHA1を使用して、インデックス付けされる文字列を生成することは好ましくありません。MD5やSHA1などのハッシュ関数によって生成される文字列の分布は、インデックスの効率を低下させる大きなスペースではランダムであり、INSERTおよびSELECTステートメントの速度を低下させる可能性があります。ここではそれを説明する記事です:code-epicenter.com/...
Mr.M

これは古いスレッドなのでおaび申し上げますが、私の質問はこれに直接関係していますが、上記の記事や他の同様の記事を読んでも、自分のニーズに対する明確な答えを得ることができません。私のシナリオは次のとおりです。現在のところ、1つのテーブルのみで構成される非常に初歩的なストックシステムを開発しています。APIを介して外部からアクセスされるため、すべての構成は他の場所に保持されます。これが、単一のテーブルのみが必要な理由です。インデックス作成について考えている2つの列には、長さが20文字未満の一意のエントリがそれぞれ約200個あります。インデックスの追加を検討すべきですか?
マイク

これは検索のような左向きlike 'a%'ですか?
会計士م18年

18

MySQLでは、プレフィックス付きインデックスを定義できます。つまり、インデックスを作成する元の文字列の最初のN文字を定義します。トリックは、選択性を高めるのに十分ですが、スペースを節約するのに十分短いNを選択することです。プレフィックスは、列全体にインデックスを付ける場合と同じくらいインデックスを有用にするのに十分な長さでなければなりません。

先に進む前に、いくつかの重要な用語を定義しましょう。インデックスの選択性、合計の個別のインデックス値と合計行数の比率です。テストテーブルの例を次に示します。

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

最初の文字(N = 1)のみをインデックス付けすると、インデックステーブルは次の表のようになります。

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

この場合、インデックスの選択性はIS = 1/3 = 0.33に等しくなります。

インデックス文字の数を2に増やした場合(N = 2)に何が起こるか見てみましょう。

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

このシナリオでは、IS = 2/3 = 0.66です。これは、インデックスの選択性を高めたことを意味しますが、インデックスのサイズも増やしました。トリックは、最大のインデックス選択性をもたらす最小数Nを見つけることです。

データベーステーブルの計算を実行できる方法は2つあります。このデータベースダンプのデモンストレーションを行います

テーブルemployeesのlast_name列をインデックスに追加し、最適なインデックス選択性が得られる最小数Nを定義するとします。

まず、最も頻繁に使用される姓を特定します。

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)

ご覧のように、姓のババが最もよく使用されます。次に、5文字のプレフィックスで始まる、最も頻繁に発生するlast_nameプレフィックスを見つけます。

+-----+--------+
| 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)

すべての接頭辞の出現回数がはるかに多いため、値が前の例とほぼ同じになるまで数値Nを増やす必要があります。

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    |
+-----+-----------+

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)

これは非常に良い結果です。つまり、最初の10文字のみをインデックス付けして、last_name列にインデックスを作成できます。テーブル定義列のlast_nameはとして定義されてVARCHAR(16)おり、これはエントリごとに6バイト(または姓にUTF8文字がある場合はそれ以上)を保存したことを意味します。このテーブルには、1637個の異なる値に6バイトを掛けたものが約9KBあり、テーブルに数百万行が含まれる場合にこの数がどのように増加するかを想像してください。

あなたは多くの計算の他の方法読み取ることができるNを私のポストにMySQLでの同一キーのインデックスを

インデックスを作成する必要がある値を生成するためにMD5およびSHA1関数を使用することも、適切なアプローチではありません。どうして?ポストで読むMySQLデータベースの主キーに適切なデータ型を選択する方法


これは、別の質問に対する非常に詳細な回答です。
ムスタッチョ

1
私をからかってるの?
Mr.M

何が間違っているのか、何が質問に当てはまらないのか説明できますか?
Mr.M

2
やあMrD 私は実際にあなたの答えが好きです。どうして ?私の昔の答えで、提案#1で言った:If you index like this, you can either look for the whole string or do left-oriented LIKE searches。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:。あなたの答えは、巨大なキーを使用してはならず、左端の文字にインデックスを付ける必要がある理由を適切に示しています。あなたの答えはここにあります。+1して回答し、DBA StackExchangeへようこそ。
-RolandoMySQLDBA
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.