3

現在、log というテーブルには約 200 万件のレコードがあります。クエリのパフォーマンスは許容できなくなりますが、現在の段階でテーブルを別のパーティションに分割したくありません。したがって、クエリのパフォーマンスを向上させるために、いくつかのインデックスを追加しようとしています。

CREATE TABLE log
           (
                id Integer primary key autoincrement,
                app_id text,
                __key__id INTEGER,

                secret text,
                trace_code text,
                url text,

                action text,

                facebook_id text,
                ip text,

                tw_time timestamp,
                time timestamp,

                tag text,
                to_url text,

                from_url text,
                referer text,

                weight integer,
                Unique(app_id, __key__id)
            );
CREATE INDEX key1 on log (action, url, tag);

ただし、sqlite はインデックスを無視してテーブル全体をスキャンしているようです。何か見逃しましたか?

sqlite> explain query plan select count(*) from log where action like 'content_%
';
0|0|0|SCAN TABLE log (~1182357 rows)


sqlite> explain query plan select count(*) from log where action like 'content_%
' group by url, tag;
0|0|0|SCAN TABLE log (~1182357 rows)
0|0|0|USE TEMP B-TREE FOR GROUP BY

編集1

@MaxSemありがとう、クエリを次のように変更すると、はるかに良くなることがわかりました。

sqlite> explain query plan select count(*) from log indexed by key1 where action
 in ('content_click','content_mouseover', 'content_display');
0|0|0|SEARCH TABLE log USING COVERING INDEX key1 (action=?) (~886770 rows)
0|0|0|EXECUTE LIST SUBQUERY 1

ただし、Sqlite が元のクエリを処理できない理由は説明できません。

EDIT2

質問を変更する必要があります。sqlite でこの種のクエリを高速化する方法はありますか?

4

2 に答える 2

5

SQLiteは、LIKEクエリで開始した場合でも、LIKE述語を使用したクエリにインデックス付き列を使用できないと思います。ただし、この種のLIKE述語を不等式でエミュレートできます。

sqlite>テーブルtの作成(アクションテキスト、URLテキスト、タグテキスト);
sqlite> t値に挿​​入('クリック'、'foo'、'バー');
sqlite> t値に挿​​入('clack'、'foo'、'bar');
sqlite> t値に挿​​入('clock'、'foo'、'bar');
sqlite> t値に挿​​入('cluck'、'foo'、'bar');
sqlite> t値に挿​​入('cleck'、'foo'、'bar');
sqlite> t値に挿​​入('clyck'、'foo'、'bar');
sqlite> t(action、url、tag);にインデックスt_indexを作成します。

LIKEで開始すると、フルスキャンが実行されます。

sqlite> Explain Query Plan Select count(*)from t where action like'cl%';
0 | 0 | 0 |スキャンテーブルt(〜500000行)

しかし、不等式では、インデックスが使用されます。

sqlite> Explain Query Plan Select count(*)from t where action> ='cl' and action <'cm';
0 | 0 | 0 |カバーインデックスを使用したテーブルの検索t_index(action>?AND action <?)(〜62500行)

この手法の注意点は、辞書式順序で期待どおりの下限(ここでは「cm」)を選択する際に注意する必要があることです。この手法では、すべてのLIKE述語を簡単にモデル化することはできません。

トークンを使用してIN述語を使用して完全に一致させる場合、等式の使用に戻るため、もちろんインデックスが使用されます。

sqlite> Explain Query Plan Select count(*)from t where action in('click'、'clack');
0 | 0 | 0 |カバーインデックスを使用したテーブルの検索t_index(action =?)(〜20行)
0 | 0 |0|実行リストサブクエリ1

引き続きLIKEを使用する場合は、サブクエリから必要なアクション値の事前に選択されたリストを使用してテーブルを結合できます。

sqlite> Explainクエリプランselectcount(*)from t join(select from t from t where action like'cl%')a where t.action = a.action;
1 | 0 | 0 |カバーインデックスを使用したテーブルのスキャンt_index(〜500000行)
0 | 0 | 1 | SCAN SUBQUERY 1 AS a(〜500000行)
0 | 1 | 0 |カバーインデックスを使用したテーブルの検索t_index(action =?)(〜10行)

これにより、基本的に、可能なすべての値を明示的にリストする代わりに、必要に応じて動的なIN述語が得られます。

もちろん、ここでは、大きなテーブルからLIKEクエリに一致するアクションのリストを抽出しているので、それ自体がフルスキャンであり、すべての利点が無効になりますが、スキーマを正規化して別の(はるかに小さい)アクションを使用する場合ログテーブルのアクション列として使用する小さな整数の代理キーを持つテーブル。ログテーブルに繰り返し文字列を何度も(小さな整数に置き換えて)保存することを避ければ、簡単に保存できます。あなたの質問のためにそれらに参加してください。

于 2012-07-31T08:58:53.227 に答える
2

あなたは必要になるでしょう:

PRAGMA case_sensitive_like=ON;

SQLite のデフォルトでは、大文字と小文字を区別しない LIKE 演算子を使用します。一般に、大文字と小文字を区別しないこととインデックスはうまくいきません。データベースで大文字と小文字を区別しないインデックスを使用することは可能ですが、余分な複雑さとシークは価値がありません。

case_sensitive_like をオンにすると、SQLite はクエリにインデックスを使用する必要があります。

于 2014-05-28T06:07:48.990 に答える