web-dev-qa-db-ja.com

SELECT FROM LIKEステートメントは、設計の観点からどのくらいの費用がかかりますか?

大規模なディレクトリ構造でランダムにアクセスする必要がある小さな静的ファイルの数が増え続けることについて、制御不能になった状況があります。私はそれらのファイルの数を非常にすぐに大幅に減らす必要があります。私は圧力を解放するための迅速な解決策を調査しています。

1つのオプションは、ファイルのコンテンツ(UTF8テキスト)をデータベースに移動し、SELECTsを実行して(名前による)ファイル検索を置き換えることです。 selectステートメントは次のようになります。

SELECT TOP(1) MyContent FROM MyTable WHERE MyContentName LIKE 'criteria%';
SELECT TOP(1) MyContent FROM MyTable WHERE MyContentName LIKE '%othercriteria';
SELECT TOP(1) MyContent FROM MyTable WHERE MyContentName LIKE '%andanothercriteria%';

800K行のテーブルで1日あたり合計200Kのリクエストについて話している(それが役立つ場合は、2つに簡単に分割できる)。 MyContentNameはキーの一部であり、インデックスが作成されます。テーブルの基準に一致するエントリが1つあるか、まったくないかのいずれかです。

私はDB管理の専門家ではありません。これは共有サーバー上のMySQLインスタンスがサポートできるものですか、それとも期待が高すぎますか?

典型的な答えは次のとおりです。テストする必要があります。残念ながら、緊急事態のため、テストを行う時間はありません。一時的であっても、サービス応答の遅延が多少低下しても、迅速な解決策を見つける必要があります。

この戦略に関する経験豊富なDB管理者の意見を探しています。ヒントと提案も大歓迎です。

3

ファイルシステムを微調整できず(たとえば、小さいブロックサイズを使用して)、本当にデータベースを使用する必要がある場合は、次のように読みます。

1つ目は、インデックスで最も一般的に使用されるデータ構造であるBツリーについて説明します。 2番目は、MySQLがBツリーを使用する方法を説明します。 3番目のコマンドは、コマンドEXPLAIN SELECT ...について説明します。これは、MySQLがクエリプランを記述する方法です(テーブルスキャンを実行している場合、使用しているインデックス(存在する場合)を通知します。これは絶対に避ける必要があります)。

最適化されたインデックスを作成するには、最初に必要なクエリの構造について検討する必要があります。たとえば、select content from files where firstParameter = XXX and secondParameter like 'xxx%'のようになります。

各列のcardinalityを分析する必要があります(つまり、列が持つことができるさまざまな値の数)。

カーディナリティが最も高い列をインデックスの最初に選択し、カーディナリティが低い列を最後に残しました。例:行が2M行あり、firstParameterが1から1Mの数字でランダムに分散され、secondParameterがファイルの所有者のフルネームであるとします。このような状況では、(firstParameter, secondParameter)句を使用すると、平均して2行しかないため、firstParameter = XXXというインデックスをこの順序で使用する必要があります。一方、secondParameterのカーディナリティははるかに低く、人の名前の可能性は100万未満です。したがって、インデックスが(secondParameter, firstParameter)の場合、where firstParameter = 1 and secondParameter like 'bruno%'クエリは最初にsecondParameterbrunoで始まるすべての行を検索します(これは数万または数十万になる可能性があります)。他の状態を探します。

また、インデックスは左から右に使用されることに注意してください。つまり、ABCの3つの列があり、(A, B, C)にインデックスを付けると、where A = 1 and C = 2などのクエリではインデックスがほとんど役に立たなくなります。 A = 1に一致する行を見つけるために使用される可能性がありますが、その後すべての行C = 2がチェックされます。ほとんどのクエリがそのようなクエリである場合(一部はBを指定する場合もあります)、インデックスは(A, C, B)にする必要があります。

最後に、like 'xxx%'はインデックスを使用できますが、like '%xxx'(またはlike '%xxx%')は使用できません。これも、インデックスが左から右に読み取られるためです。 xxx%に一致させるために、どこから検索を開始するかがわかっています。 %xxxに一致させるには、すべての行をチェックする必要があります。

インデックスについて述べたことはすべて、基準を作り直して、より構造化されたものにすることを強くお勧めします。あなたが言ったように、あなたは何かを事前に計算しようとすることができます。

コンテンツのサイズなど、その他の考慮事項があります。 8KB未満に収めることができる場合(UTF-8を使用する場合は3000文字のようになります)、InnoDBはデータを主キーと同じページに格納します。それ以外の場合は、データを別の場所に格納します。主キーでクエリする場合、最初のケースでは単一の読み取り操作があります。別のインデックスでクエリする場合、2番目のケースでは、3つの読み取り操作があります。1つは一致する行の主キーを見つけるため、もう1つは主キーによって行を見つけるため(データのアドレスを読み取るため)、およびデータを読み取るためです。 。

おお、サーバーのRAM=の量を確認してください。理想的には、データ(または少なくともインデックス)がRAMに収まる必要があります。

これらのすべての点を考慮すれば、まったく問題はないはずです。サーバーのハードウェアやその負荷(共有されていると言ったので)はわかりませんが、インデックスを微調整すると、800k行は何にも近くありません;私は専門家とはほど遠く、上記のすべてを行うことで、毎日1,000万行、数億行の(非常に最適化された)テーブルを使用して作業しており、クエリは超高速です。

お役に立てば幸いです。テーブルを作成したら、create tableステートメントを示し、データ(サイズ、カーディナリティなど)と使用する選択クエリについて少し説明して、最適化されたインデックスの作成を手伝ってもらうことができます。 。

6
Bruno Reis

速度が遅い場合は、MyISAMテーブルを使用し、FULLTEXT INDEXを追加することをお勧めします。全文検索は、特殊な種類のインデックス(明らかに全文)に基づく検索の一種です。この場合、パフォーマンスは非常に最適ですが、%%のように常にテーブル全体のテーブルスキャンが発生します(100kの場合)などの行)。

このリンクを参照できます: http://www.gammelsaeter.com/programming/mysql-fulltext-search-example/

2
Mahesh Patil