Personal tools
You are here: Home ブログ 井上 sqlite-3.5.5のOpcode
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Recent entries
Apache2.4のリリース予定は来年(2011年)初め(あくまで予定) inoue 2010-12-23
Herokuの発音 inoue 2010-12-20
雑誌記事「ソフトウェア・テストPRESS Vol.9」の原稿公開 inoue 2010-12-18
IPA未踏のニュース inoue 2010-12-15
労基法とチキンゲーム inoue 2010-12-06
フロントエンドエンジニア inoue 2010-12-03
ASCII.technologies誌にMapReduceの記事を書きました inoue 2010-11-25
技術評論社パーフェクトシリーズ絶賛発売中 inoue 2010-11-24
雑誌連載「Emacsのトラノマキ」の原稿(part8)公開 inoue 2010-11-22
RESTの当惑 inoue 2010-11-22
「プログラマのためのUXチートシート」を作りました inoue 2010-11-19
「ビューティフルコード」を読みました inoue 2010-11-16
Categories
カテゴリなし
 
Document Actions

sqlite-3.5.5のOpcode

で、驚きのリリース文と書きましたが、どれほどの変化か調べてみました。簡単なSQLではあまり変わりません(当り前?)。

今まで

pushを暗黙に行う命令
pushを暗黙に行う命令
pop,popを暗黙に行う命令

だったのが、

命令。結果をレジスタ1に格納
命令。結果をレジスタ2に格納
命令。レジスタ1とレジスタ2を引数

になるだけです。

以下、sqlite-3.4.2とsqlite-3.5.5の比較です。

sqlite-3.4.2で、単純なselectをした結果は次のようになりました。単純化するために、カラムは全部文字列にしています。

sqlite> CREATE TABLE my (title text, author text, body text);
sqlite> .explain
sqlite> EXPLAIN SELECT title FROM my WHERE author = 'foo';
addr  opcode          p1          p2          p3
----  --------------  ----------  ----------  ---------------------------------
0     Goto            0           13
1     Integer         0           0
2     OpenRead        0           6
3     SetNumColumns   0           2
4     Rewind          0           11
5     Column          0           1
6     String8         0           0           foo
7     Ne              353         10          collseq(BINARY)
8     Column          0           0
9     Callback        1           0
10    Next            0           5
11    Close           0           0
12    Halt            0           0
13    Transaction     0           0
14    VerifyCookie    0           10
15    Goto            0           1
16    Noop            0           0

以下、addrカラム値がnの行をn行目と呼びます。

初期化の部分を無視すると、ループを形成しているのは、5行目から10行目です。10行目のNextは、レコードがあれば5行目にジャンプ、無ければ次の行(Close)に進みます。 5行目は1番目のカラムの値をスタックに積みます。カラムは0ベースなので、この場合、authorカラムです。6行目は文字列"foo"をスタックに積みます。7行目のNeは、勘が良ければ分かると思いますが、not equalの略で、スタックからふたつの値をポップして比較します。not equalが成立すると、10行目に飛びます。10行目はNextなので、このジャンプはcontinue相当です。8行目のColumnは0番目のカラム(titleカラム)の値をスタックに積みます。9行目のCallback命令は、スタックから値をポップして、ユーザアプリのコールバック関数を呼びます。sqliteの結果セットは、レコード単位でコールバック関数が呼ばれます。

同じことをsqlite-3.5.5ですると次のようになりました。

sqlite> EXPLAIN SELECT title FROM my WHERE author = 'foo';
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Trace          0     0     0     explain select title from my where author = 'foo';  00
1     Goto           0     13    0                    00
2     OpenRead       0     6     0                    00
3     SetNumColumns  0     2     0                    00
4     Rewind         0     11    0                    00
5     Column         0     1     1                    00
6     String8        0     2     0     foo            00
7     Ne             2     10    1     collseq(BINARY)  69
8     Column         0     0     3                    00
9     ResultRow      3     1     0                    00
10    Next           0     5     0                    00
11    Close          0     0     0                    00
12    Halt           0     0     0                    00
13    Transaction    0     0     0                    00
14    VerifyCookie   0     10    0                    00
15    TableLock      0     6     0     my             00
16    Goto           0     2     0                    00

ループも含めてほとんど変わりません(Callbackの代わりにResultRowになった程度)。5行目と6行目は、それぞれスタックに積まずに、レジスタ1とレジスタ2(それぞれp2で指定されています)に値をセットします。そして、7行目のNeはp1とp3で指定されたレジスタ(つまり1と2)の値を比較して、(not equalが)成立すると(p2で指定された)10行目に飛びます。

インデックスが使われる場合も見てみます。

以下はsqlite-3.4.2の結果です。

sqlite> CREATE INDEX idx_my ON my(author);
sqlite> EXPLAIN SELECT title FROM my WHERE author = 'foo';

addr  opcode          p1          p2          p3
----  --------------  ----------  ----------  ---------------------------------
0     Goto            0           21
1     Integer         0           0
2     OpenRead        0           6
3     SetNumColumns   0           2
4     Integer         0           0
5     OpenRead        1           7           keyinfo(1,BINARY)
6     String8         0           0           foo
7     IsNull          -1          18
8     MakeRecord      1           0           a
9     MemStore        0           0
10    MoveGe          1           18
11    MemLoad         0           0
12    IdxGE           1           18          +
13    IdxRowid        1           0
14    MoveGe          0           0
15    Column          0           0
16    Callback        1           0
17    Next            1           11
18    Close           0           0
19    Close           1           0
20    Halt            0           0
21    Transaction     0           0
22    VerifyCookie    0           11
23    Goto            0           1
24    Noop            0           0

OpenReadが2つ(2行目と4行目)あります。4行目のOpenReadはインデックスのオープンです。それぞれp1の値が、それぞれの識別子です(Unixのシステムコール風に言えば、ファイルディスクリプタ相当です)。

ループは11行目から17行目です。

10行目のMoveGeで、インデックス上の"foo"の最初の位置を指します。12行目のIdxGEはインデックス上の値と"foo"を比較して、一致しなければ(正確には名前から推測できるようにgreater than or equalの演算)、18行目に飛んでループを抜けます。14行目のMoveGeはrowid(レコードを一意に識別するid)を使って、テーブル内のポインタ(カーソル)を動かします。

以下はsqlite-3.5.5の結果です。

sqlite> EXPLAIN SELECT title FROM my WHERE author = 'foo';
addr  opcode         p1    p2    p3    p4             p5  commeaddr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Trace          0     0     0     explain select title from my where author = 'foo';  00
1     Goto           0     19    0                    00
2     OpenRead       0     6     0                    00
3     SetNumColumns  0     2     0                    00
4     OpenRead       1     7     0     keyinfo(1,BINARY)  00
5     SetNumColumns  1     2     0                    00
6     String8        0     2     0     foo            00
7     IsNull         2     16    0                    00
8     MakeRecord     2     1     1     ab             00
9     MoveGe         1     16    1                    00
10    IdxGE          1     16    1                    01
11    IdxRowid       1     5     0                    00
12    MoveGe         0     0     5                    00
13    Column         0     0     6                    00
14    ResultRow      6     1     0                    00
15    Next           1     10    0                    00
16    Close          0     0     0                    00
17    Close          1     0     0                    00
18    Halt           0     0     0                    00
19    Transaction    0     0     0                    00
20    VerifyCookie   0     11    0                    00
21    TableLock      0     6     0     my             00
22    Goto           0     2     0                    00

ループは10行目から15行目です。

9行目のMoveGeで、インデックス上の"foo"の位置を指します。10行目のIdxGEはインデックス上の値と"foo"を比較して、一致しなければ、16行目に飛んでループを抜けます。12行目のMoveGeはrowidを使って、テーブル内のポインタ(カーソル)を動かします。

ほとんど変わりませんが、少し命令が減っています。sqlite-3.4.2にあったMemStoreとMemLoadが無くなっていますが、これらは元々レジスタを扱うような命令だったので、無くなっているようです。

参考URL

The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/inoue/sqlite-opcode/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.