web-dev-qa-db-ja.com

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

私は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)VARCHAR(150)FULLTEXTまたはINDEXキーを使用する必要がありますか?
2)文字数を150から220または250に増やすと、大きな違いが生じますか? (それを計算する方法はありますか?)
言ったように、それらは一意になるため、myFieldは- 主キー。すでにVARCHAR INDEX/FULLTEXTであるフィールドにPRIMARY KEYを追加することはまれではありませんか?

43
Mark Tower

提案#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');

試してみる !!!

69
RolandoMySQLDBA

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つの方法があります。 this database dump でデモを行います。

last_name in table employeesをインデックスに追加し、最小数を定義したいとしましょう[〜#〜] 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)
_

ご覧のように、姓Babaが最も頻繁に使用されます。次に、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)
_

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

[〜#〜] n [〜#〜]の数を計算する他の方法を私の投稿で読むことができます MySQLのプレフィックスインデックス

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

18
Mr.M