上篇文章簡單討論了虛擬機的原理,這篇文章咱們詳細討論下指令,具體從幾種典型的SQL語句來看看每種SQL對應的指令流,以及每一個指令的含義。經過explain語句,能夠看到語句對應的指令流;經過pragma vdbe_trace=on指令,咱們甚至能夠獲得語句對應的指令執行流程,包括跳轉等。
測試表結構html
CREATE TABLE t1( id integer primary key autoincrement, user_id int, c1 varchar(1000), c2 varchar(1000) );
測試語句
(1)INSERTsql
sqlite> explain insert into t1(user_id,c1,c2) values(1111,'abc','abc'); 0|Init|0|17|0||00|Start at 17
1|OpenWrite|0|5|0|4|00|root=5 iDb=0; t1 2|NewRowid|0|4|2||00|r[4]=rowid 3|MemMax|2|4|0||00|r[2]=max(r[2],r[4]) 4|SoftNull|5|0|0||00|r[5]=NULL
5|Integer|1111|6|0||00|r[6]=1111
6|String8|0|7|0|abc|00|r[7]='abc'
7|String8|0|8|0|abc|00|r[8]='abc'
8|MakeRecord|5|4|9|DDBB|00|r[9]=mkrec(r[5..8]) 9|Insert|0|9|4|t1|1b|intkey=r[4] data=r[9]
10|Close|0|0|0||00|
11|OpenWrite|0|3|0|2|00|root=3 iDb=0; sqlite_sequence 12|NotNull|3|14|0||00|if r[3]!=NULL goto 14
13|NewRowid|0|3|0||00|r[3]=rowid 14|MakeRecord|1|2|10||00|r[10]=mkrec(r[1..2]) 15|Insert|0|10|3||08|intkey=r[3] data=r[10]
16|Halt|0|0|0||00|
17|Transaction|0|1|4|0|01|
18|TableLock|0|5|1|t1|00|iDb=0 root=5 write=1
19|TableLock|0|3|1|sqlite_sequence|00|iDb=0 root=3 write=1
20|OpenRead|0|3|0|2|00|root=3 iDb=0; sqlite_sequence 21|Null|0|2|3||00|r[2..3]=NULL
22|String8|0|1|0|t1|00|r[1]='t1'
23|Rewind|0|31|0||00|
24|Column|0|0|2||00|r[2]=
25|Ne|1|29|2||10|if r[1]!=r[2] goto 29
26|Rowid|0|3|0||00|r[3]=rowid 27|Column|0|1|2||00|r[2]=
28|Goto|0|31|0||00|
29|Next|0|24|0||00|
30|Integer|0|2|0||00|r[2]=0
31|Close|0|0|0||00|
32|Goto|0|1|0||00|
經過explain咱們獲得了語句對應的指令流,該語句總共包含了32條指令,下面咱們逐條來講明指令的含義。測試
|
指令spa |
含義日誌 |
0code |
Init|0|17|0||00|Start at 17sqlite |
指令從P2(17)開始htm |
1blog |
OpenWrite|0|5|0|4|00|root=5 iDb=0; t1 |
打開表t1讀寫遊標cursor0,P4,表示總共有4列 |
2 |
NewRowid|0|4|2||00|r[4]=rowid |
生成一個newRowid,寫入P2寄存器,P3寄存器存儲的是目前最大值,當rowid達到最大值,則SQLITE_FULL error。 |
3 |
MemMax|2|4|0||00|r[2]=max(r[2],r[4]) |
取出sqlite_sequence裏面和表裏面記錄的最大值 |
4 |
SoftNull|5|0|0||00|r[5]=NULL |
初始化r[5]爲null,rowid列 |
5 |
Integer|1111|6|0||00|r[6]=1111 |
設置寄存器r[6]爲1111 |
6 |
String8|0|7|0|abc|00|r[7]='abc' |
設置寄存器r[7]爲abc |
7 |
String8|0|8|0|abc|00|r[8]='abc' |
設置寄存器r[8]爲abc |
8 |
MakeRecord|5|4|9|DDBB|00|r[9]=mkrec(r[5..8]) |
生成t1表記錄 將寄存器r[5..8]的內容轉爲記錄格式,存入r[9],P2指定長度爲4。 |
9 |
Insert|0|9|4|t1|1b|intkey=r[4] data=r[9] |
插入 key在r[4]中,data在r[9]寄存器中 |
10 |
Close|0|0|0||00| |
關閉遊標 |
11 |
OpenWrite|0|3|0|2|00|root=3 iDb=0; sqlite_sequence |
打開寫遊標 |
12 |
NotNull|3|14|0||00|if r[3]!=NULL goto 14 |
r[3]不爲null,則跳轉14 |
13 |
NewRowid|0|3|0||00|r[3]=rowid |
生成新的rowid |
14 |
MakeRecord|1|2|10||00|r[10]=mkrec(r[1..2]) |
生成sqlite_sequence記錄 生成記錄,r[1]=t1,r[2]=seq |
15 |
Insert|0|10|3||08|intkey=r[3] data=r[10] |
插入 key=r[3],data=r[10] |
16 |
Halt|0|0|0||00| |
終止 |
17 |
Transaction|0|1|4|0|01| |
打開一個新事務,建立回滾日誌文件 |
18 |
TableLock|0|5|1|t1|00|iDb=0 root=5 write=1 |
上t1表鎖(僅用於shared-cache) |
19 |
TableLock|0|3|1|sqlite_sequence|00|iDb=0 root=3 write=1 |
上sqlite_sequence表鎖 |
20 |
OpenRead|0|3|0|2|00|root=3 iDb=0; sqlite_sequence |
打開sqlite_sequence表,P4,表示總共2列 |
21 |
Null|0|2|3||00|r[2..3]=NULL |
初始化寄存器爲NULL |
22 |
String8|0|1|0|t1|00|r[1]='t1' |
設置r[1]爲t1 |
23 |
Rewind|0|31|0||00| |
重置遊標cursor P1,遊標指向索引的第一個位置,若是tree爲空,則跳轉到31,不然執行下面的指令 |
24 |
Column|0|0|2||00|r[2]= |
獲取cusor P1指向記錄的P2th列,即sqlite_sequence的name列,結果存在r[2]中 |
25 |
Ne|1|29|2||10|if r[1]!=r[2] goto 29 |
若是sqlite_sequence表中記錄與當前的表名不一致,跳轉到29 |
26 |
Rowid|0|3|0||00|r[3]=rowid |
獲取當前記錄的rowid |
27 |
Column|0|1|2||00|r[2]= |
獲取當前記錄的第1列,結果存放在r[2]中,sqlite_sequence的第一列是seq值 |
28 |
Goto|0|31|0||00| |
跳轉到31 |
29 |
Next|0|24|0||00| |
遊標日後移,若是還有記錄,則跳轉到P2(24),不然繼續日後執行。 |
30 |
Integer|0|2|0||00|r[2]=0 |
這是r[2]爲0 |
31 |
Close|0|0|0||00| |
關閉sqlite_sequence表的遊標 |
32 |
Goto|0|1|0||00| |
跳轉到1,開始執行插入表t1 |
經過pragma命令,設置vdbe_trace爲on能夠看到SQL語句對應的指令流是如何運行的,具體以下:能夠看到,指令並非順序執行的,而是存在跳轉,具體的執行順序,由代碼生成器生成指令流和指令的內容決定。
sqlite> pragma vdbe_trace=on; sqlite> insert into t1(user_id,c1,c2) values(1111,'abc','abc'); SQL: [insert into t1(user_id,c1,c2) values(1111,'abc','abc');] VDBE Trace: 0 Init 0 17 0 00 Start at 17 17 Transaction 0 1 4 0 01 18 TableLock 0 5 1 t1 00 iDb=0 root=5 write=1 19 TableLock 0 3 1 sqlite_sequence 00 iDb=0 root=3 write=1 20 OpenRead 0 3 0 2 00 root=3 iDb=0; sqlite_sequence 21 Null 0 2 3 00 r[2..3]=NULL REG[2] = NULL 22 String8 0 1 0 t1 00 r[1]='t1' REG[1] = t2[t1](8) 23 Rewind 0 31 0 00 24 Column 0 0 2 00 r[2]= REG[2] = s4[user](8) 25 Ne 1 29 2 10 if r[1]!=r[2] goto 29 REG[1] = t2[t1](8) REG[2] = s4[user](8) 29 Next 0 24 0 00 24 Column 0 0 2 00 r[2]= REG[2] = s6[orders](8) 25 Ne 1 29 2 10 if r[1]!=r[2] goto 29 REG[1] = t2[t1](8) REG[2] = s6[orders](8) 29 Next 0 24 0 00 24 Column 0 0 2 00 r[2]= REG[2] = s2[t1](8) 25 Ne 1 29 2 10 if r[1]!=r[2] goto 29 REG[1] = t2[t1](8) REG[2] = s2[t1](8) 26 Rowid 0 3 0 00 r[3]=rowid REG[3] = i:3 27 Column 0 1 2 00 r[2]= REG[2] = i:113 28 Goto 0 31 0 00 31 Close 0 0 0 00 32 Goto 0 1 0 00 1 OpenWrite 0 5 0 4 00 root=5 iDb=0; t1 2 NewRowid 0 4 2 00 r[4]=rowid REG[2] = i:113 REG[4] = i:114 3 MemMax 2 4 0 00 r[2]=max(r[2],r[4]) REG[4] = i:114 4 SoftNull 5 0 0 00 r[5]=NULL 5 Integer 1111 6 0 00 r[6]=1111 REG[6] = i:1111 6 String8 0 7 0 abc 00 r[7]='abc' REG[7] = t3[abc](8) 7 String8 0 8 0 abc 00 r[8]='abc' REG[8] = t3[abc](8) 8 MakeRecord 5 4 9 DDBB 00 r[9]=mkrec(r[5..8]) REG[9] = s13[05000213130457616263616263......Wabcabc](8) 9 Insert 0 9 4 t1 1B intkey=r[4] data=r[9] REG[9] = s13[05000213130457616263616263......Wabcabc](8) REG[4] = i:114 10 Close 0 0 0 00 11 OpenWrite 0 3 0 2 00 root=3 iDb=0; sqlite_sequence 12 NotNull 3 14 0 00 if r[3]!=NULL goto 14 REG[3] = i:3 14 MakeRecord 1 2 10 00 r[10]=mkrec(r[1..2]) REG[10] = s6[031101743172...t1r](8) 15 Insert 0 10 3 08 intkey=r[3] data=r[10] REG[10] = s6[031101743172...t1r](8) REG[3] = i:3 16 Halt 0 0 0 00
(2)SELECT
sqlite> explain select rowid,user_id,c2 from t1 where rowid=112;
0|Init|0|12|0||00|Start at 12
1|OpenRead|0|5|0|4|00|root=5 iDb=0; t1
2|Explain|0|0|0|SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)|00|
3|Integer|112|1|0||00|r[1]=112
4|MustBeInt|1|10|0||00|
r[p1]中的值必需爲int,或能夠轉爲int,若是不能跳轉到10。
5|NotExists|0|10|1||00|intkey=r[1]; pk
P3是rowid,查找表,判斷是否有rowid記錄,若是沒有,則跳轉10
6|Copy|1|2|0||00|r[2]=r[1]
7|Column|0|1|3||00|r[3]=t1.user_id
讀取第1列到寄存器r[3]
8|Column|0|3|4||00|r[4]=t1.c2
讀取第3列到寄存器r[4]
9|ResultRow|2|3|0||00|output=r[2..4]
生成結果集
10|Close|0|0|0||00|
11|Halt|0|0|0||00|
關閉全部打開的遊標,P1是返回給用戶的錯誤碼,根據P2值肯定是否須要rollback。
12|Transaction|0|0|7|0|01|
13|TableLock|0|5|0|t1|00|iDb=0 root=5 write=0
14|Goto|0|1|0||00|
(3)UPDATE
sqlite> explain update t1 set user_id=888 where rowid=111;
addr|opcode|p1|p2|p3|p4|p5|comment
0|Init|0|16|0||00|Start at 16
1|Null|0|1|2||00|r[1..2]=NULL
2|OpenWrite|0|5|0|4|00|root=5 iDb=0; t1
打開寫遊標
3|Explain|0|0|0|SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)|00|
4|Integer|111|7|0||00|r[7]=111
5|MustBeInt|7|8|0||00|
6|NotExists|0|8|7||00|intkey=r[7]; pk
查不到則跳轉8
7|Rowid|0|2|0||00|r[2]=rowid
8|IsNull|2|15|0||00|if r[2]==NULL goto 15
沒有找到,跳轉15結束
9|Null|0|3|0||00|r[3]=NULL
10|Integer|888|4|0||00|r[4]=888
11|Column|0|2|5||00|r[5]=t1.c1
12|Column|0|3|6||00|r[6]=t1.c2
13|MakeRecord|3|4|8|DDBB|00|r[8]=mkrec(r[3..6])
新建record
14|Insert|0|8|2|t1|05|intkey=r[2] data=r[8]
同一個rowid,進行覆蓋。
15|Halt|0|0|0||00|
16|Transaction|0|1|7|0|01|
開啓寫事務
17|TableLock|0|5|1|t1|00|iDb=0 root=5 write=1
對錶t1上寫鎖
18|Goto|0|1|0||00|
(4)DELETE
sqlite> explain delete from t1 where rowid=111;
addr|opcode|p1|p2|p3|p4|p5|comment
0|Init|0|11|0||00|Start at 11
1|Null|0|1|0||00|r[1]=NULL
2|OpenWrite|0|5|0|4|00|root=5 iDb=0; t1
3|Explain|0|0|0|SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)|00|
4|Integer|111|2|0||00|r[2]=111
5|MustBeInt|2|8|0||00|
6|NotExists|0|8|2||00|intkey=r[2]; pk
7|Goto|0|9|0||00|
8|Goto|0|10|0||00|
9|Delete|0|1|0|t1|00|
刪除遊標所指的記錄
10|Halt|0|0|0||00|
11|Transaction|0|1|7|0|01|
12|TableLock|0|5|1|t1|00|iDb=0 root=5 write=1
13|Goto|0|1|0||00|
小結
經過上面的INSERT,SELECT,UPDATE,DELETE語句,我簡單介紹了語句中包含的指令,以及指令的含義。通過這個過程,相信你們對SQLite執行流程有了更深的認識,也更能理解指令是如何存取數據的。SQLite中總共包含了100多條指令,對於每條指令的詳細含義能夠參考官方文檔:https://www.sqlite.org/opcode.html