3

SQLite データベースに単純なテーブル (約 8 列と多数の行) があります。サービスとして実行され、テーブルでかなり頻繁に (約 5 分ごとに) 選択、更新、および挿入を実行する単一のプログラムがあります。選択は、更新する行を決定するためにのみ使用され、ブール値を保持する列に基づいています (おそらく SQLite によって内部的に整数に変換されます)。

また、Web ユーザーがデータの一部を表示したい場合にいつでも (常に GROUP BY 句を使用して) 選択を実行する Web アプリケーションもあります。

Web アプリケーションを介してデータを要求するには、次の 2 つの方法があります。(a) 定義済みフィルター (つまり、where 句には 3 つの特定の列に特定の条件がある)、(b) カスタム フィルター (つまり、ユーザーが条件の値を選択しますが、 where 句に参加する列は (a)) と同じです。前述のように、どちらの場合も GROUP BY 操作があります。

ビューまたはカスタム関数を使用するとパフォーマンスが向上するかどうか疑問に思っています。現在、「カスタム」選択が完了するまでに 30 秒以上かかる場合があります。これは、データがユーザーに送り返される前です。

編集:「事前定義された」選択ステートメントで EXPLAIN QUERY PLAN を使用すると、1 行のみが生成されます。

0|0|TABLE mytable

同じクエリで EXPLAIN を使用すると、次の結果が得られます。

0|OpenVirtual|1|4|keyinfo(2,-BINARY,BINARY)
1|OpenVirtual|2|3|keyinfo(1,BINARY)
2|MemInt|0|5|
3|MemInt|0|4|
4|Goto|0|27|
5|MemInt|1|5|
6|Return|0|0|
7|IfMemPos|4|9|
8|Return|0|0|
9|AggFinal|0|0|count(0)
10|AggFinal|2|1|sum(1)
11|MemLoad|0|0|
12|MemLoad|1|0|
13|MemLoad|2|0|
14|MakeRecord|3|0|
15|MemLoad|0|0|
16|MemLoad|1|0|
17|Sequence|1|0|
18|Pull|3|0|
19|MakeRecord|4|0|
20|IdxInsert|1|0|
21|Return|0|0|
22|MemNull|1|0|
23|MemNull|3|0|
24|MemNull|0|0|
25|MemNull|2|0|
26|Return|0|0|
27|Gosub|0|22|
28|Goto|0|82|
29|Integer|0|0|
30|OpenRead|0|2|
31|SetNumColumns|0|9|
32|Rewind|0|48|
33|Column|0|8|
34|String8|0|0|123456789
35|Le|356|39|collseq(BINARY)
36|Column|0|3|
37|Integer|180|0|
38|Gt|100|42|collseq(BINARY)
39|Column|0|7|
40|Integer|1|0|
41|Ne|356|47|collseq(BINARY)
42|Column|0|6|
43|Sequence|2|0|
44|Column|0|3|
45|MakeRecord|3|0|
46|IdxInsert|2|0|
47|Next|0|33|
48|Close|0|0|
49|Sort|2|69|
50|Column|2|0|
51|MemStore|7|0|
52|MemLoad|6|0|
53|Eq|512|58|collseq(BINARY)
54|MemMove|6|7|
55|Gosub|0|7|
56|IfMemPos|5|69|
57|Gosub|0|22|
58|AggStep|0|0|count(0)
59|Column|2|2|
60|Integer|30|0|
61|Add|0|0|
62|ToReal|0|0|
63|AggStep|2|1|sum(1)
64|Column|2|0|
65|MemStore|1|1|
66|MemInt|1|4|
67|Next|2|50|
68|Gosub|0|7|
69|OpenPseudo|3|0|
70|SetNumColumns|3|3|
71|Sort|1|80|
72|Integer|1|0|
73|Column|1|3|
74|Insert|3|0|
75|Column|3|0|
76|Column|3|1|
77|Column|3|2|
78|Callback|3|0|
79|Next|1|72|
80|Close|3|0|
81|Halt|0|0|
82|Transaction|0|0|
83|VerifyCookie|0|1|
84|Goto|0|29|
85|Noop|0|0|

私が使用した選択は次のとおりです

SELECT 
    COUNT(*) as number, 
    field1, 
    SUM(CAST(filter2 +30 AS float)) as column2 
FROM 
    mytable 
WHERE 
    (filter1 > '123456789'  AND filter2 > 180) 
    OR filter3=1 
GROUP BY 
    field1 
ORDER BY 
    number DESC, field1;
4

1 に答える 1

1

非主キー フィールドの比較を行う場合は常に、フィールドにインデックスを追加することをお勧めします。ただし、多すぎるとINSERTがクロールする可能性があるため、それに応じて計画してください。

また、ブール値のみを保持するような単純なフィールドがある場合は、宣言したものではINTEGERなく として宣言することを検討することをお勧めします。SQLite で明確に定義されていない型として宣言すると、値を比較するのに時間がかかる型がデフォルトにNUMERICdoubleなります。

IMO、GROUP BY並べ替えディレクティブは、最適化されていないクエリに完全に当てはまらない場合があります。その方法論には、最初からデータベースから引き出されていなければ、事前に削除できたはずの冗長データを削除することが含まれます。

編集:

あなたのクエリを見て、それを最適化するためにできる簡単なことがいくつかあることを知りました。

  • SUM(CAST(filter2 +30 AS float))非効率的です。なぜフロートとしてキャストするのですか?それだけSUMで30 *を追加しないのはなぜCOUNTですか?

  • filter1 > '123456789'- なぜ文字列を比較するのですか? 整数比較だけを使用しないのはなぜですか?

于 2012-05-07T15:34:53.460 に答える