• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            SQLite虛擬機(jī)工作原理

            SQLite中的虛擬數(shù)據(jù)庫引擎
            如果你想知道SQLite內(nèi)部是如何運(yùn)行的,你需要粗略了解一下VDBE的工作原理,從下圖可以看出,VDBE處于系統(tǒng)運(yùn)行的中部,所以它似乎與大部分的部件都有關(guān)系,即使部分代碼不直接與它交互但還是起到了支持作用的,VDBE確實(shí)是SQLite的核心部分。
            clip_image001

            這部分將要介紹VDBE是如何工作的,特別是VDBE指令是如何在一起配合完成對(duì)數(shù)據(jù)庫的操作的,下面先用一些簡(jiǎn)單的例子介紹,然后再解決更加復(fù)雜的問題,如果讀完了這篇文章,你就會(huì)對(duì)SQLite如何工作有了很好的理解了。
            前言
            VDBE
            是用虛擬機(jī)語言來操作虛擬機(jī)的,每個(gè)程序的目的都是要訪問和更新數(shù)據(jù)庫,那么VDBE要執(zhí)行的虛擬機(jī)語言都是專門為查找、讀取、和修改數(shù)據(jù)庫而做的。
            每個(gè)VDBE語言指令都包括一個(gè)操作符和三個(gè)操作數(shù),分別為P1P2P3P1是一個(gè)任意的整數(shù),P2是一個(gè)非負(fù)整數(shù),P3是一個(gè)指向一個(gè)數(shù)據(jù)結(jié)構(gòu)或者是一個(gè)字符串,也可能是NULL,只有少數(shù)VDBE指令用到所有的操作數(shù),很多只用一兩個(gè)而已,還有一大部分根本就不用而是把自己的數(shù)據(jù)存到執(zhí)行棧中。
            一個(gè)VDBE程序從第0條指令開始并執(zhí)行后面的一連串指令直到遇到錯(cuò)誤或者執(zhí)行到一個(gè)HALT指令。當(dāng)一個(gè)VDBE完成執(zhí)行任務(wù)后,所有的數(shù)據(jù)游標(biāo)都關(guān)閉了,所有的內(nèi)存都釋放,所有的數(shù)據(jù)都從棧中彈出,所以從來不用擔(dān)心內(nèi)存泄漏和沒有釋放資源的問題。

            一、向數(shù)據(jù)庫中插入數(shù)據(jù)
            我們開始用只有很少指令的VDEB程序來解決一個(gè)問題,假設(shè)我們已經(jīng)有一個(gè)數(shù)據(jù)表:
            CREATE TABLE examp(one text, two int);
            也就是說我們現(xiàn)在已經(jīng)存在一個(gè)叫examp名字的表和兩列分別叫onetwo,現(xiàn)在假設(shè)我們一插入下面的數(shù)據(jù):INSERT INTO examp VALUES(‘Hello, World!’,99);
            現(xiàn)在我們就可以看一下這些指令,我們可以先打開SQLite3命令窗口,并且建立好上面的表,并且插入數(shù)據(jù),插入語句這樣寫:
            EXPLAIN INSERT INTO examp VALUES('Hello, World!',99);
            這時(shí)就會(huì)有下面的指令表產(chǎn)生:
            clip_image002

            從上面可以看出,對(duì)于一個(gè)簡(jiǎn)單的插入語句它執(zhí)行了12條指令,前三條和后2條都是指令執(zhí)行的開始和結(jié)尾,而真正執(zhí)行的工作都是在中間7條完成的,這里沒有跳轉(zhuǎn),程序從上面一直到下面執(zhí)行,現(xiàn)在一條條的解釋其含義:
            0 Transaction 0 0
            1 VerifyCookie 0 81
            2 Transaction 1 0
            指令Transaction是在開始一個(gè)事務(wù),事務(wù)是如果遇到Commit或者Rollback操作符就結(jié)束。P1是指示這個(gè)事務(wù)所在的數(shù)據(jù)庫文件的索引,0表示是主數(shù)據(jù)庫文件,當(dāng)一個(gè)事務(wù)開始時(shí),在數(shù)據(jù)庫文件上要加上寫鎖,當(dāng)一個(gè)事務(wù)在運(yùn)行的時(shí)候其它的進(jìn)程就不能讀或者寫這個(gè)文件了,開始一下事務(wù)也會(huì)產(chǎn)生一個(gè)回滾日志,在數(shù)據(jù)庫文件發(fā)生任何修改之前事務(wù)必須開始。
            指令VerifyCookie是檢查數(shù)據(jù)模式的版本來確保它與它在上次讀數(shù)據(jù)庫模式得到的信息是一致的。P1是數(shù)據(jù)庫編號(hào)(0表示主數(shù)據(jù)庫),這樣是為了確保數(shù)據(jù)庫模式?jīng)]有被其它的線程修改。
            第二個(gè)Transaction指令是在開始一個(gè)事務(wù)并且對(duì)數(shù)據(jù)庫1產(chǎn)生一個(gè)日志文件,這個(gè)數(shù)據(jù)是用于臨時(shí)表的。

            3 Integer 0 0
            4 OpenWrite 0 3 examp
            指令Integer是將一個(gè)整型值P10)放到棧中,這里的0表示將要修改的數(shù)據(jù)庫,如果P3不為NULL,那么它將是用一個(gè)字符串類型來表達(dá)同樣的整數(shù)。現(xiàn)在棧的狀態(tài)為:
            (integer) 0

            指令OpenWrite是在P10)數(shù)據(jù)庫中,對(duì)表examp表打開一個(gè)讀/寫游標(biāo),它的根頁面是P2(在這個(gè)數(shù)據(jù)庫文件中是3),游標(biāo)可以是任意一個(gè)非負(fù)整數(shù),但是VDBE是在一個(gè)數(shù)組中分配游標(biāo)的,這個(gè)數(shù)組的大小為最大游標(biāo)數(shù)加一,所以為了節(jié)省內(nèi)存,最好就是從0位置開始一直加上去。這里的P3是將要被打開的表名,但是這里并沒有使用它,只是為了更好的讀代碼。這條指令會(huì)把數(shù)據(jù)庫編號(hào)0從棧中彈出來,所以現(xiàn)在棧又變成空的了。

            5 NewRecno 0 0
            指令NewRecno是產(chǎn)生一個(gè)新的整數(shù)記錄來讓游標(biāo)P1指向它,這個(gè)記錄值現(xiàn)在還不被用作關(guān)鍵字,新的記錄被存入棧中,現(xiàn)在棧的狀態(tài)如下:
            (integer) new record key


            6 String 0 0 Hello, World!
            指令String是將操作數(shù)P3放入棧中,現(xiàn)在棧的狀態(tài)為:
            (string) "Hello, World!"
            (integer) new record key


            7 Integer 99 0 99
            Integer
            指令是將操作數(shù)P1放入棧中,現(xiàn)在棧的狀態(tài)為:
            (integer) 99
            (string) "Hello, World!"
            (integer) new record key


            8 MakeRecord 2 0
            MakeRecord
            指令是將P12個(gè))棧頂數(shù)據(jù)彈出棧,并且將它們轉(zhuǎn)換成二進(jìn)制類型的數(shù)據(jù)來存入數(shù)據(jù)庫方件中,被這條指令處理過的記錄又一次壓入棧中,現(xiàn)在棧的狀態(tài)為:
            (string) "Hello, World!"
            99
            (integer) new record key


            9 PutIntKey 0 1
            指令PutIntKey是從棧彈出兩個(gè)數(shù)據(jù)并且將這兩個(gè)數(shù)據(jù)寫入游標(biāo)P1所指的表中,這個(gè)新的記錄如果已經(jīng)存在則被覆蓋,如果不存在則新創(chuàng)建。這條記錄的值是棧頂記錄,而主鍵則是棧中第二條記錄(注:也就是在SQLite每個(gè)表中的系統(tǒng)主鍵rowid)這條指令會(huì)使棧彈出兩次,因?yàn)椴僮鲾?shù)P21,所以行的改變數(shù)為1并且rowid會(huì)存儲(chǔ)到sqlite_last_insert_rowid()函數(shù)的返回值中,如果P20,那么行修改數(shù)就不會(huì)改變,這條指令就說明插入操作所做的工作。

            10 Close 0 0
            指令Close是關(guān)閉一個(gè)先前打開的游標(biāo)P1,如果P1現(xiàn)在處于關(guān)閉狀態(tài)則這條指令無操作。

            11 Commit 0 0
            指令Commit會(huì)使所有的改變都存儲(chǔ)到數(shù)據(jù)庫中,在下一個(gè)事務(wù)開始之前再不會(huì)產(chǎn)生任何的修改,這條指令也會(huì)刪除日志文件并且釋放了數(shù)據(jù)庫鎖,如果游標(biāo)還是在打開狀態(tài)的話,一個(gè)讀鎖可以繼續(xù)持有。

            12 Halt 0 0
            指令Halt使得VDBE引擎立即退出,所有打開的游標(biāo)等都自動(dòng)關(guān)閉,操作數(shù)P1sqlite_exec()接口的返回值,對(duì)于一個(gè)正常的Halt,返回應(yīng)該是SQLITE_OK (0).,如果是出現(xiàn)錯(cuò)誤,就可能會(huì)得到其它的信息,P2操作數(shù)只有出現(xiàn)錯(cuò)誤時(shí)候才會(huì)用到,也有一個(gè)隱含的Halt指令“Halt 0 0 0”在每個(gè)程序的結(jié)尾,這是VDBE在準(zhǔn)備執(zhí)行的時(shí)候附加上去的。

            接著上一節(jié)的插入原理,現(xiàn)在來講一下查詢的執(zhí)行原理: 

            二、簡(jiǎn)單的查詢
            到現(xiàn)在為止,已經(jīng)知道VDBE是如何將數(shù)據(jù)寫入數(shù)據(jù)庫中的了,現(xiàn)在下來看看查詢是如何工作的,下面是我們用到的例子:SELECT * FROM examp;
            下面就是對(duì)執(zhí)行這條SQL語句產(chǎn)生的指令:
            clip_image003

            在看這個(gè)問題之前我們還是先看一下SQLite的查詢是如何工作的,這樣我們才知道我們需要完成什么工作,對(duì)于查詢結(jié)果的每一行,SQLite都會(huì)調(diào)用一個(gè)Callback函數(shù):
            int Callback(void *pUserData, int nColumn, char *azData[], char *azColumnName[]);
            SQLite
            庫會(huì)給VDBE提供一個(gè)指向回調(diào)函數(shù)的指針和一個(gè)pUserData指針(不管是回調(diào)函數(shù)指針還是pUserData指針,它都是由API函數(shù)sqlite_exec()傳進(jìn)來的)VDBE的工作就是為nColumnazData[]azColumnName[]取值,nColumn就是查詢結(jié)果的列數(shù),azColumnName[]數(shù)組中的每個(gè)字符串就是查詢結(jié)果的每一列名,azData[]放的是實(shí)際的數(shù)據(jù)。


            0 ColumnName 0 0 one
            1 ColumnName 1 0 two
            VDBE
            的查詢程序的前兩條指令是為azColumn設(shè)置值的,ColumnName指令是告訴VDBE應(yīng)該給azColumnName數(shù)組設(shè)置什么值的,每次查詢都是以ColumnName指令開始的,對(duì)查詢結(jié)果的每個(gè)列都會(huì)有這樣的指令。并且在后來的查詢中對(duì)于每一列都會(huì)有相應(yīng)的列指令。

            2 Integer 0 0
            3 OpenRead 0 3 examp
            4 VerifyCookie 0 81
            指令23打開一個(gè)要訪問的數(shù)據(jù)庫表的游標(biāo),這人工作和在插入數(shù)據(jù)時(shí)候用到的OpenWrite指令是差不多的,除了這回打開是用來讀的而那個(gè)是寫的,指令4象在插入的例子中一樣是用來驗(yàn)證數(shù)據(jù)庫模式的

            5 Rewind 0 10
            指令Rewind是初始化一個(gè)對(duì)要查詢表的循環(huán)的迭代器,它把游標(biāo)定位到表的第一個(gè)數(shù)據(jù)上,這是Column指令和下一條指令所需要的,下一條指令將會(huì)用這個(gè)游標(biāo)迭代整個(gè)表的,如果這個(gè)表是空的則跳轉(zhuǎn)到P210),如果表不是空的,則就跳到下一條指令,從現(xiàn)在開始就到了循環(huán)體部分了。

            6 Column 0 0
            7 Column 0 1
            8 Callback 2 0
            上面的指令是整個(gè)循環(huán)體,它對(duì)表中的每一條記錄都是只執(zhí)行一次,上面67指令都是將P2操作數(shù)對(duì)應(yīng)的各自的列的數(shù)據(jù)放到棧中,在這個(gè)例子中,第6條指令是將one列中的數(shù)據(jù)放到棧中,而第7條指令是將two列中的數(shù)據(jù)放到棧中,第8條指令是引發(fā)對(duì)回調(diào)函數(shù)的執(zhí)行,這時(shí)它的P1操作數(shù)將會(huì)變成查詢結(jié)果的列數(shù),這條指令會(huì)將P1條記錄出棧并放到azData[]數(shù)組中。

            9 Next 0 6
            這條指令是在執(zhí)行一個(gè)循環(huán)的分叉部分,從第5條指令到現(xiàn)在是構(gòu)成了整個(gè)循環(huán)的邏輯結(jié)構(gòu),這是個(gè)應(yīng)該值得注意的關(guān)鍵概念,這個(gè)指令是將游標(biāo)前進(jìn)指向下一條記錄,如果前進(jìn)成功,那么立即跳轉(zhuǎn)到這個(gè)循環(huán)開始,如果這個(gè)前進(jìn)不成功,則繼續(xù)執(zhí)行下面的結(jié)束循環(huán)的指令,而不跳回。

            10 Close 0 0
            11 Halt 0 0
            Close
            指令是在程序的結(jié)尾將指向要查詢表的游標(biāo)關(guān)閉,其實(shí)沒必要在這里執(zhí)行這條指令,因?yàn)樵诔绦蚪Y(jié)束后,VDBE都會(huì)把所有的游標(biāo)自動(dòng)的關(guān)閉,Halt指令是用來關(guān)閉VDBE程序的。
            注意到查詢記錄時(shí)沒有用到TransactionCommit指令,而在插入的時(shí)候用到了,因?yàn)?span lang="EN-US">SELECT
            是個(gè)讀操作,而不會(huì)改變數(shù)據(jù)庫,所以它不需要事務(wù)。

             

            posted on 2009-06-20 03:16 肥仔 閱讀(804) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 數(shù)據(jù)庫

            亚洲女久久久噜噜噜熟女| 婷婷久久五月天| 久久精品国产影库免费看| 精品亚洲综合久久中文字幕| 99久久中文字幕| 久久久久无码中| 色欲久久久天天天综合网| 国产成人久久精品区一区二区| 久久亚洲国产午夜精品理论片| 香蕉99久久国产综合精品宅男自 | 国产精品9999久久久久| 91久久成人免费| 一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 国产高潮国产高潮久久久| 久久男人中文字幕资源站| 日本久久久久亚洲中字幕| 久久久久国产日韩精品网站| 久久久久99精品成人片直播| 久久嫩草影院免费看夜色| 四虎国产精品免费久久5151| 亚洲精品美女久久久久99| 日本精品久久久久久久久免费| .精品久久久麻豆国产精品| 久久久久久久91精品免费观看| 99久久亚洲综合精品成人| 久久综合九色综合网站| 精品无码久久久久国产动漫3d| 久久99精品久久久久久水蜜桃| 久久精品亚洲精品国产色婷| 狠狠色丁香婷婷久久综合五月| 精品久久久久久久久久中文字幕 | 亚洲中文字幕无码久久2020| 久久精品女人天堂AV麻| 久久AAAA片一区二区| 中文字幕亚洲综合久久2| 久久美女网站免费| 久久久精品免费国产四虎| 精品国产91久久久久久久| 好属妞这里只有精品久久| 久久成人精品视频| 久久99国产精品二区不卡|