• <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

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數據加載中……

            SQLite虛擬機工作原理

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

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

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

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

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

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

            5 NewRecno 0 0
            指令NewRecno是產生一個新的整數記錄來讓游標P1指向它,這個記錄值現在還不被用作關鍵字,新的記錄被存入棧中,現在棧的狀態如下:
            (integer) new record key


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


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


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


            9 PutIntKey 0 1
            指令PutIntKey是從棧彈出兩個數據并且將這兩個數據寫入游標P1所指的表中,這個新的記錄如果已經存在則被覆蓋,如果不存在則新創建。這條記錄的值是棧頂記錄,而主鍵則是棧中第二條記錄(注:也就是在SQLite每個表中的系統主鍵rowid)這條指令會使棧彈出兩次,因為操作數P21,所以行的改變數為1并且rowid會存儲到sqlite_last_insert_rowid()函數的返回值中,如果P20,那么行修改數就不會改變,這條指令就說明插入操作所做的工作。

            10 Close 0 0
            指令Close是關閉一個先前打開的游標P1,如果P1現在處于關閉狀態則這條指令無操作。

            11 Commit 0 0
            指令Commit會使所有的改變都存儲到數據庫中,在下一個事務開始之前再不會產生任何的修改,這條指令也會刪除日志文件并且釋放了數據庫鎖,如果游標還是在打開狀態的話,一個讀鎖可以繼續持有。

            12 Halt 0 0
            指令Halt使得VDBE引擎立即退出,所有打開的游標等都自動關閉,操作數P1sqlite_exec()接口的返回值,對于一個正常的Halt,返回應該是SQLITE_OK (0).,如果是出現錯誤,就可能會得到其它的信息,P2操作數只有出現錯誤時候才會用到,也有一個隱含的Halt指令“Halt 0 0 0”在每個程序的結尾,這是VDBE在準備執行的時候附加上去的。

            接著上一節的插入原理,現在來講一下查詢的執行原理: 

            二、簡單的查詢
            到現在為止,已經知道VDBE是如何將數據寫入數據庫中的了,現在下來看看查詢是如何工作的,下面是我們用到的例子:SELECT * FROM examp;
            下面就是對執行這條SQL語句產生的指令:
            clip_image003

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


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

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

            5 Rewind 0 10
            指令Rewind是初始化一個對要查詢表的循環的迭代器,它把游標定位到表的第一個數據上,這是Column指令和下一條指令所需要的,下一條指令將會用這個游標迭代整個表的,如果這個表是空的則跳轉到P210),如果表不是空的,則就跳到下一條指令,從現在開始就到了循環體部分了。

            6 Column 0 0
            7 Column 0 1
            8 Callback 2 0
            上面的指令是整個循環體,它對表中的每一條記錄都是只執行一次,上面67指令都是將P2操作數對應的各自的列的數據放到棧中,在這個例子中,第6條指令是將one列中的數據放到棧中,而第7條指令是將two列中的數據放到棧中,第8條指令是引發對回調函數的執行,這時它的P1操作數將會變成查詢結果的列數,這條指令會將P1條記錄出棧并放到azData[]數組中。

            9 Next 0 6
            這條指令是在執行一個循環的分叉部分,從第5條指令到現在是構成了整個循環的邏輯結構,這是個應該值得注意的關鍵概念,這個指令是將游標前進指向下一條記錄,如果前進成功,那么立即跳轉到這個循環開始,如果這個前進不成功,則繼續執行下面的結束循環的指令,而不跳回。

            10 Close 0 0
            11 Halt 0 0
            Close
            指令是在程序的結尾將指向要查詢表的游標關閉,其實沒必要在這里執行這條指令,因為在程序結束后,VDBE都會把所有的游標自動的關閉,Halt指令是用來關閉VDBE程序的。
            注意到查詢記錄時沒有用到TransactionCommit指令,而在插入的時候用到了,因為SELECT是個讀操作,而不會改變數據庫,所以它不需要事務。

             

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

            久久久久亚洲av成人网人人软件| 97久久精品午夜一区二区| 久久精品国产99国产精品| 久久久精品国产亚洲成人满18免费网站 | 亚洲av日韩精品久久久久久a | 国产精品久久影院| 国产ww久久久久久久久久| 久久婷婷国产剧情内射白浆| 97久久精品无码一区二区| 四虎亚洲国产成人久久精品| 久久国产高潮流白浆免费观看| 中文字幕亚洲综合久久| 99久久精品国产一区二区 | 国产成人久久精品二区三区| 亚洲精品成人网久久久久久| 国产精品久久久久9999| 精品久久久久成人码免费动漫| 99麻豆久久久国产精品免费| 国产精品久久久久久久久久影院 | 亚洲国产精品无码成人片久久| 婷婷综合久久中文字幕| 午夜久久久久久禁播电影| 国产综合成人久久大片91| 99久久免费国产精精品| 精品久久亚洲中文无码| 一日本道伊人久久综合影| 国产成人精品久久一区二区三区av | 国产精品免费久久久久电影网| 亚洲中文字幕无码久久精品1| 精品久久久久久国产免费了| 久久久久久久尹人综合网亚洲| 亚洲va久久久噜噜噜久久| 一97日本道伊人久久综合影院| 久久久国产精品| 久久久久久极精品久久久| 精品综合久久久久久88小说 | 日日狠狠久久偷偷色综合0| 国产成人无码精品久久久久免费| 久久精品草草草| 66精品综合久久久久久久| 93精91精品国产综合久久香蕉|