-1

ファイルパスを保存したいテーブルがあるので、サイズ4096(LinuxのデフォルトのMAX_PATHサイズ)のvarcharフィールドがあります。ただし、特定のディレクトリ内のすべてのファイルパスのクエリを実行できる必要があるため、次のようなクエリを実行することを考えていました。

SELECT * 
FROM files_table 
WHERE files_table.path LIKE "/my/awesome/dir/%"

パスフィールドをUNINDEXEDにしてデータベースでこれを実行すると、約10秒かかります。テーブルのサイズが約400万で、インデックス付けされていないフィールドであることを考えると、しばらく時間がかかることがわかります。ただし、インデックスサイズを500にしてインデックスを作成すると、クエリ時間が急増します...最大で約30秒になります。

これは私には非常に混乱しているようです。何がこれを引き起こしているのかについて誰かが何か考えを持っていますか?


より多くのデータに飢えている人のために:

少し余分なデータとして-クエリで「explain」を実行してみたところ、実際にインデックスを使用していることがわかりましたが、key_lenは5つしか報告されていません。これも奇妙に思えます。

また、私の質問に対する良い答えを聞きたいのですが(ここで何が起こっているのかを理解したいので!)、「なぜそれが行われているのかわかりませんが、そうではありません。重要なのは、データベースをこのように設計する必要があるからです...」そのように傾倒している人のために、私が本当にやろうとしているのは、大規模なネットワークファイルシステムからのさまざまな(キャッシュされた)データのクエリを実行するデータベース構造を構築することです。ファイルパスを保存するだけがおそらくこれにアプローチする最も素朴な方法であることを私は知っていますが、私はそれをファーストパス実装として試してみて、それがどこに到達したかを確認すると思いました。


編集:

したがって、もう少し掘り下げ/情報:実際のインデックスは複数列のインデックスです-最初のインデックスはintであり、batch_idを保持します(つまり、テーブルはファイルシステムに関するキャッシュされた情報を保持するため、各スナップショットは独自のbatch_idを取得します)、 2つ目は、パスvarcharの部分インデックスです。したがって、EXPLAINがインデックスkey_lenを言うとき、その最初の4バイトは実際にはbatch_id用です。つまり、パスのインデックスは1バイトしかないということです。

ああ、「実際の」クエリはbatch_idにも制限があるので、次のようになります。

SELECT * 
FROM files_table 
WHERE batch_id=5 
  AND files_table.path LIKE "_globalSoft/my/awesome/dir/%"

次に、データベース内のファイルの大部分が「_」で始まるパスを持っています-上記のクエリの「_globalSoft」はその一例です。(はい、パスはすべて相対的です。)したがって、key_lenが5しかない場合、キーで使用されている唯一の文字が先頭の「_」である可能性があります。これは、なぜこれほど遅いのかを説明します。

もちろん、これでも、なぜ先頭の「_」のみを使用しているのかという疑問が生じます。MySQLインデックスのドキュメント(http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html)を読んでいると、次の行に気づきました。

文字列は自動的にプレフィックスとエンドスペースで圧縮されます。13.1.8項「CREATEINDEX構文」を参照してください。

残念ながら、与えられたリンクは文字列プレフィックス圧縮について何も述べておらず、私はそれについて多くの情報を見つけるのに苦労しています。私が見つけた情報はすべてMyISAMに関するものであり、現在InnoDBを使用しています。(ただし、MyISAMに切り替えるのは理にかなっているかもしれませんが、文字列の方が優れていると思われます。)

4

3 に答える 3

0

MySQLは全体としてより多くのIOを実行する必要があるため、クエリは遅くなります。インデックスは最初の500文字のみをカバーし、最初の500文字はあまり一意ではありません。プレフィックスインデックスの場合、MySQLはプレフィックスと一致する必要があり、次に行をフェッチして、完全な値がプレフィックス値と一致するかどうかを調べます。一般的なプレフィックスの場合、これにより大量の余分なランダムIOが生成される可能性があります。ランダムIOは、シーケンシャルIOよりも大幅にコストがかかります。インデックスがないと、シーケンシャルIOを使用したテーブルのシングルパスが実行され、クエリが高速になります。

このタイプの検索にMySQLを使用したくない場合があります。Sphinx、Solr、またはその他のテキスト索引付けテクノロジーを調べ、単語の区切り文字として「/」を使用してパスに索引付けします。

また、テーブルをN個の小さなテーブルに分割し、N個のテーブルを並列に全表スキャンすることもできます。

于 2012-08-04T02:16:57.050 に答える
0

いくつのレコードが返されますか?おそらくレコードのかなりの割合を返しているようです。また、インデックスからデータを1つずつ選択するよりも、1回のパスでデータをスキャンする方が明らかに効率的です。

少し単純化しすぎると、インデックスの使用には通常、3つの(実際にはキャッシュされた)読み取りタスクが含まれます。ソートされたキーのリストで値を見つけるための1つ。これは、プライマリインデックスのレコードへのキーを提供します。1つはプライマリインデックスを調べて、テーブル内のレコード位置を見つけるためのものです。テーブル内のレコードを見つけるための1つ。

また、「カーディナリティ」をグーグルで検索して、データとインデックスがどの程度適格かを確認してください。

于 2012-08-06T18:38:15.727 に答える
0

FACEPALM

わかりました、私はばかです...問題は、「globalSoft」のようなディレクトリ(つまり、アンダースコアで始まるディレクトリ)を照合していて、「 」が特殊文字(%など)であることに気づかなかったことです。それを逃れませんでした。

私の愚かさを許してください!

于 2012-08-06T21:23:38.773 に答える