2016-04-19 12 views
0

私はこのような行を持つテーブルと呼ばれる非常に大きなインデックスなしのテーブル持ってWHEREを選択:最速の方法インデックスなしのテーブルの上に句

IP    entrypoint    timestamp 
171.128.123.179 /page-title/?kw=abc  2016-04-14 11:59:52 
170.45.121.111 /another-page/?kw=123 2016-04-12 04:13:20 
169.70.121.101 /a-third-page/   2016-05-12 09:43:30 

は、私が30個のIP与えられ、最速のクエリを作りたいです1つの日付は、その日付の前に1週間前に行を検索し、各IPに対して「?kw =」を含む最新の行を戻します。だから、私はDISTINCTエントリーポイントが必要ですが、最新のエントリーポイントだけが必要です。

私はそれが比較的単純なINNER JOINであることを知っていますが、私はそれを行う最速の方法を知らない。

ところで、インデックスは非常に大きく、ウェブサイトを提供しているデータベースであるため、インデックスを追加できません。インデックス付きのテーブルに置き換えるつもりですが、心配はありません。

+4

クエリが何であれ、速度は遅くなり、速度の差は最小限に抑えられます。 Mysqlはすべて索引に関するものです。 – cpugourou

+0

インデックスがない場合、エンジンはフルテーブルスキャンを実行する必要があります。制限句がある場合、早期に停止する可能性がありますが、実行できるショートカットはありません。 (わからない場合は、クエリでEXPLAINを実行してください。) –

+1

「非常に大きい」の大きさは? –

答えて

0

含まれているテーブルからの行だけ過去週間以内に

SELECT ... 
    FROM very_big_unindexed_table t 

...

WHERE t.timestamp >= NOW() + INTERVAL - 1 WEEK 

は '?キロワット=' エントリポイントで

AND t.entrypoint LIKE '%?kw=%' 

のみ各IPの最新の行それにはいくつかのアプローチがあります。非常に大きな索引付けされていない表の相関サブクエリは、あなたのランチとランチボックスを食べます。また、索引がなければ、表と「ファイル・ポートの使用」操作を完全にスキャンすることはありません。

パフォーマンスが悪い場合は、できるだけ小さくしてから並べ替えを実行し、結合操作(そのテーブルに戻る)を避けて相関関係を避けるサブクエリ。

だから、先週の行のすべてのを「?kw =」というエントリポイントで返してみましょう。これは

  SELECT t.ip 
       , t.timestamp 
       , t.entry_point 
      FROM very_big_unindexed_table t 
      WHERE t.timestamp >= NOW() + INTERVAL -1 WEEK 
      AND t.entrypoint LIKE '%?kw=%' 
      ORDER BY t.ip DESC, t.timestamp DESC 

我々は、ユーザー定義変数と、サポートされていないトリックを使用することができます...完全なテーブルのスキャン、およびソート操作になるだろう。動作は(正式に)未定義。非公式には、MySQL 5.1および5.5(少なくとも)非常に予測可能である。

私はこれがあると思うでオプティマイザであるため、(MySQLのリファレンスマニュアルには具体的には、このようなパターンを使用しないように警告し先週の行の数がテーブル全体の重要なサブセットである場合、あなたが得ようとしているものと同程度になるでしょう。これは、行がたくさんある場合には、かなりの中間結果セット(派生テーブル)それらは述語を満たす。

SELECT q.ip 
    , q.entrypoint 
    , q.timestamp 
    FROM (
     SELECT IF(t.ip = @prev_ip, 0, 1) AS new_ip 
       , @prev_ip := t.ip   AS ip 
       , t.timestamp    AS timestamp 
       , t.entrypoint    AS entrypoint 
      FROM (SELECT @prev_ip := NULL) i 
      CROSS 
      JOIN very_big_unindexed_table t 
      WHERE t.timestamp >= NOW() + INTERVAL -1 WEEK 
      AND t.entrypoint LIKE '%?kw=%' 
      ORDER BY t.ip DESC, t.timestamp DESC 
     ) q 
WHERE q.new_ip 

そのクエリの実行(時間を取るために何が起こっているかの点で)が必要になります

  • テーブルのフルスキャン(その周りを取得する方法はありません)
  • ソート
  • 述語を満足するすべての行を含む導出表をマテリアライズして、導出表を通過させてeの「最新」行を引き出す(述語を満足する行をすべて含む)。
  • ach IP
+0

あなたの説明をお寄せいただき、ありがとうございます。 –