• 締切済み

検索条件が複数の場合のインデックスの張り方

Mysql5.0 + ASP.NETで開発中です。 サーバーはWindows2003サーバーです。 とある検索サイトを作っていますが、1テーブルのフィールド数が80くらいあります。 また、レコード数は常時100万件程度です。 このテーブルの検索を行うときに、ユーザーが任意の検索条件を設定できるような画面なのですが、実際に検索に使用されるフィールド数は最大で10です。 例えば、where a = 999 and b = 999 や where a = 999 and c = 999 and f = 999 や where b = 999 and d = 999 and f = 999 and g = 999 など、where句で使用されるフィールドがユーザーの指定により常に異なります。(999は任意の値です) ORDER BYに使用されるフィールド数は3です。 現状ではインデックスは張っていないため、かなり検索速度が遅いため、インデックスを張りたいのですが、どのような張り方がいいのかがわかりません。 このような場合、インデックスを張る方法として、どの方法が一番よいのでしょうか? 1.検索に使用される10つのフィールドに1つずつ張ればよい 2.検索に使用される10つのフィールドとソートに使用される3つのフィールドに1つずつ張ればよい 3.where句の組み合わせを全て考えて複合インデックスを張る必要がある。 4.その他 また、80フィールドのテーブルを適当に4つくらいに分けて、検索時に結合すれば早くなったりするものでしょうか?

  • MySQL
  • 回答数3
  • ありがとう数1

みんなの回答

  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.3

>10!=3628800というのはどういう意味でしょうか?  10個のフィールドから、任意の順番で任意の個数の重複しないフィールドを採取するとします。(採取したフィールドは、この順番で検索条件に&結合で使用されるとすると、あなたが提案した3番のインデックスを作成する際に必要なインデックス数となります。)  任意の個数だから、最初のフィールドの数は、F1~F10の10通り。  次のフィールドは、一個目に採取したフィールドを除いた9通り。  以下、最後まで続く。  で、場合の数は、10*9*8*・・・*2*1=10!  というのが、No2さんの回答の趣旨なんですが、実は、「任意の個数の」という条件と、or条件の組み合わせの場合がありますので、これよりも、場合の数は増えます。  ところで、インデックスを張ると、検索は早くなる「可能性があります」が、挿入・修正・削除の速度は、おそく「なります」  このトレードオフを考えると、7桁以上なんて個数のインデックスを張るのは、確実にシステムは遅くなります。現実性もありませんしね。  何故、データベースが自分で勝手にインデックスを張ってくれないかを考えましょう。使われ方によって、効率の良い張り方が違う上に、データ内容によってもその妥当性が変わるからです。  この場合は、おそらく、一番最初にする仕事は、ある期間に渡ってどんな条件で検索が行われたかの統計表を作ることだと思います。  その上で、上位の物に関してだけ結合インデックスを張るのが妥当かと思います。  最初は、上位から少しずつインデックスを作成していき、システム全体のレスポンスを見守ってください。(特に、挿入・修正・削除の効率は確実に低下しますから、その辺の監視も忘れないように。)その上で、さらにインデックスを春かどうかの決断をした方がよろしいかと思います。  ただ、楽観的に見ると、人間という物は偏りのある物ですから、統計表を見れば、「何だ。結局、数個作れば、全体の5割カバーできるのか」というつぶやきになりそうな気もします。

pinchtaro
質問者

お礼

ご回答ありがとうございます。 とりあえずは、必ず使用される検索条件をキーとしたindexを張ってみようと思います。 それにより、ほとんどの場合は10000件以下に絞られるようです。

  • javawater
  • ベストアンサー率11% (6/52)
回答No.2

10!=3628800で、このパターンのindexを貼るのは不可能でしょう。 ユーザの検索方法には偏りが必ずありますので、 その上位3つのパターンのみ暫定策としてindexを貼るのはどうでしょうか。 妙案が出れば別ですが、全カバーするのは通常無理だと思いますので、ユーザーに対して検索パターン上位三つのもののみ対策を取ります、とアナウンスするのはいかがでしょうか。

pinchtaro
質問者

補足

10!=3628800というのはどういう意味でしょうか? ユーザーの検索方法は自由なので基本的にはすべてカバーしてあげたいと思っているのですが。。。

回答No.1

>実際に検索に使用されるフィールド数は最大で10です。 検索条件は、「=」条件と限定できるのですか?また、ANDのみでORはないのですか? >ORDER BYに使用されるフィールド数は3です。 母体が約100万件とのことですが、その内、1回の検索で、最大で何件くらい検索されることになるのでしょうか? インデクスは、データの絞込みだけでなく、ソート抑止による性能向上にも有効です。ソート抑止するには、ORDER BYの列の指定とインデクスの先頭からの構成列が一致している必要があります。 >このような場合、インデックスを張る方法として、どの方法が一番よいのでしょうか? 単一の列に各々インデクスを定義する場合、各列の条件でそれぞれ絞り込み効果が高くないと、性能が改善するどころかオーバヘッド要因になる場合があります。 複数列(マルチカラム)インデクスを定義する方が、恐らく効果が高いと思います。 すべての組み合わせに定義した方がいいかどうかは、今の情報からだけでは判断できません。重複データ数などにより、結果的に特定のケースの場合は、複数列インデクスである程度絞込み、あとは表データを見る方が早い場合もあるでしょう。 また、インデクスを何本も付ける場合は、追加、更新、削除でオーバヘッド要因になることも無視できません。 >また、80フィールドのテーブルを適当に4つくらいに分けて、検索時に結合すれば早くなったりするものでしょうか? 今の情報だけでは、判断できません。 以下のURLは、MySQL 5.1のマニュアルの最適化の記述箇所です。 MySQL 5.0は英文マニュアルしかないと思うので、MySQL 5.1で違う部分もあるかも知れませんが、基本的な考え方は大きくは変わらないと思います。 http://dev.mysql.com/doc/refman/5.1/ja/optimization.html

pinchtaro
質問者

補足

ご回答ありがとうございます。 ・AND条件だけではなくOR条件もあります。 ・検索数は、条件次第ですが、検索条件を緩めると、最大で1万件くらいにはなると思います。

関連するQ&A

  • MYSQL】複数テーブルジョイン時のindexにつ

    select count(*) from テーブルa, テーブルb, テーブルc where テーブルa.フィールド1=テーブルb.フィールド1 and テーブルb.フィールド1=テーブルc.フィールド1 上記のようなクエリがあり、各フィールドにはindexが貼ってあるのですが、indexが使われないものがあるようですごく遅いです。 解決策はないでしょうか。 バージョンは5.5です

  • Access結合後の短いテキスト型のインデックス

    Accessの検索にて、テーブルA LEFT JOIN テーブルB で外部結合し、 WHERE句でテーブルBの短いテキスト型を抽出条件にすると、検索が遅くなります。 【テーブル定義】 テーブルA( ・年月日(日付/時刻、重複ありインデックス) ・コード(短テキスト、重複ありインデックス) ・属性あ(短テキスト、重複ありインデックス) ・属性い(短テキスト、重複ありインデックス) ) テーブルB( ・コード(短テキスト、主KEY) ・属性う(短テキスト、重複ありインデックス) ・属性え(数値、重複ありインデックス) ) 【件数】 テーブルA:15万件 テーブルB:500件 =====SQLここから===== SELECT * FROM テーブルA LEFT JOIN テーブルB ON テーブルA.コード = テーブルB.コード WHERE 属性あ IS NULL AND 属性い = 'あああ' AND 属性う = 'アアア' AND 属性え = 1 GROUP BY 年月日、 属性う =====SQLここまで===== この検索SQLは遅い(1分30秒くらい)のですが 『AND 属性う = 'アアア'』を削除すると 10秒くらいに速くなります。 ”属性う” のインデックスが効いてないように見えるのですが どのようにチューニングしたら速くなるでしょうか? エクセルからLAN越しにDAO接続してSQL実行してます。 AccessはOffice365(バージョン1902)です。

  • SQLで複数のテーブルと結合したUPDATE文

    普通のUPDATE文はUPDATEするテーブル名を一つ記入して UPDATE テーブルA SET フィールドA = 値A WHERE テーブルA.フィールドB = 値B みたいな感じですが、私のしたい事はと言うと UPDATE テーブルA,テーブルB,テーブルC SET A.フィールドA = 値A WHERE テーブルA.フィールドA = テーブルB.フィールドB AND テーブルB.フィールドB = テーブルC.フィールドC AND テーブルB.フィールドD = 値D AND テーブルC.フィールドE = 値E という具合に複数のテーブルがUPDATEするテーブルA以外のところで、互いに条件で結ばれており、FROM句でUPDATEしないテーブル名まで宣言しないといけなくなっています。そもそもこういうFROM句を使うUPDATE文は実行可能かも不明です。どなたか解決策お願いいたします。ちなみに開発ソフトはVBAを使っています。

  • WHERE句に複数テーブルを使いたい

    アクセス2010です。 テーブルA F1__テキスト(重複あり) F2__数字 テーブルB F1__テキスト(重複なし) F2__Boolean 条件 ・テーブルAのF2が1の条件で ・テーブルAのF1にテーブルBのF2がない ・テーブルBのF2がTrueであるものだけ DoCmd.RunSQL INSERT INTO テーブルA(F1,F2) SELECT テーブルB.F1,100 FROM テーブルB WHERE テーブルA.F2 = 1 And テーブルA.F1<>テーブルB.F1 And テーブルB.F2 = True; WHERE句に複数テーブルを使いたい時は、どのようにするのでしょうか?

  • 同じフィールドから複数条件のAND条件で抽出する方法

    お世話になります。 同じフィールドから複数条件のAND条件で抽出する方法 DBはAccessです。 フィールド1がA フィールド2がBという条件でしたら Select 抽出フィールド form テーブル where フィールド1=A and フィールド2=B で行っています。 フィールド1がAまたはBでしたら Select 抽出フィールド form テーブル where フィールド1=A or フィールド1=B で行っています。 それではフィールド1がAもBも満たす抽出はどのようにしたら良いのでしょうか。 例: 学生テーブル  フィールド 学生ID、氏名 履修科目テーブル  フィールド 学生ID、同一学生内連番、科目 というテーブル構成で英語、国語のどちらも履修している学生を抽出する場合などです。 2テーブルをリンクしたクエリを作ったのですが、 単にフィールド 学生ID、氏名、同一学生内連番、科目 なのでどちらも履修している学生を抽出できませんでした。 どのようにしたらよろしいのでしょうか。よろしくお願いいたします。

  • 複数条件による検索

    現在strutsを使用した「検索フォーム」を作成しています。 検索項目は6つあり、それぞれNOT NULLの項目と、NULL可の項目が あります。 全部NOT NULLですと、WHERE句で 「WHERE 項目A = '%?%'」 を条件にすればよいと思うのですが、NULL可の場合は 「WHERE 項目B = '%?%' OR 項目 IS NULL 」 となると思います。 しかしこれですと項目Bに検索条件で入力したものと NULL値のものが両方ヒットしてしまいます・・・ うまく文章がまとまらなくてとても恐縮ですが、 うまく構文を作る方法はないでしょうか・・・。 よろしくお願いします。

  • WHERE句の条件の記述の順序

    PRIMARY KEYとINDEXがテーブルに設定されている場合、 検索条件に記述する順番はどのようになるのでしょうか? 下記のテーブルがあり、SELECT文をつくろうと 考えています。 テーブル:foo 項目  PRIMARY KEY  INDEX ----------------------------------- a 1 b 2 1 c 3 d 2 (1)PRIMARY KEYを優先してWHERE句の順番を決める↓ SELECT * FROM foo WHERE a = "AAA" AND b = "BBB" AND c = "CCC" AND d = "DDD" (2) それともINDEXが設定されている項目を先に記述する↓ SELECT * FROM foo WHERE b = "BBB" AND d = "DDD"   AND a = "AAA" AND c = "CCC" (1)と(2)ではどちらの性能がよいのでしょうか?

  • 複数のテーブルから同じ条件で検索したい。

    例えば、テーブルがA,B,C,Dとあって、レイアウトはそれぞれ違います。 ですが、全てのテーブルに共通の項目もあります。 共通項目名:FLG このような前提で、 A,B,C,Dのデータを同じ検索条件で全ての内容を表示させたいのですができませんか? ベタに書くと select * from A where FLG='2'; select * from B where FLG='2'; select * from C where FLG='2'; select * from D where FLG='2'; と言う感じで結果を表示させたいのです。 実際にはテーブル名がものすごい数なので、ベタに書きたくないので、この部分をtab テーブルのtnameとかを使っていっぺんに検索結果が出せればありがたいのですけが・・・ こういうのはシェルとか使わないとだめですかね?(DBはオラクルです。)

  • インデックスを用いたbetween検索について

    Cで1~360000までのランダムな整数の列(col1)を含む100万件のデータを作成し(50MB弱)、 create table table1(・・・, col1 integer not null, ・・・); で作ったテーブルにload data infile文で挿入し、 create index index1 on table1(col1); でインデックスを作成しました。 select * from table1 where col1 between 1000 and 2000; といったような検索(約2500件ヒット)をしたいのですが、この検索ではインデックスを作らないテーブルのほうが速く検索できてしまいます。 select * from table1 where col1 between 100 and 200; のような検索(約250ヒット)ではインデックスの効果があり、高速検索ができますが。 環境はMySQL-5.0.26、ノートPC(256MB)、Fedora Core5、設定ファイルはMy-large.cnfを、ほぼそのまま使用しています。 上記のような少し大きめの検索範囲でもインデックスを用いた検索を改善する方法をご教授お願いします。何かのパラメータが決定的に足りないと思うのですが。

  • 複合インデックスの設定に関して

    MySQLの複合インデックスに関して質問させて頂きます。 現在検索条件に3つのカラムを使用して検索をかけているSELECT文があります。 データの件数は100万件ほどあるとします。 【例】 「SELECT * FROM test WHERE a = '1' AND b = 'xxxxx' AND c = '1';」 カラム「a」「c」は、0と1のみが格納されたカラムで、頻繁に更新されます。 カラム「b」は、同じ値が入ることがありますが、ほぼユニークな文字列が格納されます。 上記のような場合、インデックスは ・「a,b,c」の全てを設定した複合インデックスを作成するべきか。 ・cは頻繁に更新されるので、「a,b」のみの複合インデックスを作成するべきか。 ・aも同じく頻繁に更新されるので、WHERE句の検索順をbを先に持ってきて、「b」のみの単独インデックスを作成するべきか。 一概にこうだという答えは無いかもしれませんが、何か良い方法があれば教えて頂けると幸いです。 また、質問に不備な点がございましたら、ご指摘お願いいたします。

    • ベストアンサー
    • MySQL