佳木斯湛栽影视文化发展公司

主頁 > 知識(shí)庫 > SQLite教程(十一):臨時(shí)文件

SQLite教程(十一):臨時(shí)文件

熱門標(biāo)簽:呼叫中心市場需求 Linux服務(wù)器 AI電銷 地方門戶網(wǎng)站 鐵路電話系統(tǒng) 服務(wù)外包 網(wǎng)站排名優(yōu)化 百度競價(jià)排名

一、簡介:

    盡管SQLite的數(shù)據(jù)庫是由單一文件構(gòu)成,然而事實(shí)上在SQLite運(yùn)行時(shí)卻存在著一些隱含的臨時(shí)文件,這些臨時(shí)文件是出于不同的目的而存在的,對于開發(fā)者而言,它們是透明的,因此在開發(fā)的過程中我們并不需要關(guān)注它們的存在。盡管如此,如果能對這些臨時(shí)文件的產(chǎn)生機(jī)制和應(yīng)用場景有著很好的理解,那么對我們今后應(yīng)用程序的優(yōu)化和維護(hù)都是極有幫助的。在SQLite中主要產(chǎn)生以下七種臨時(shí)文件,如:

    1). 回滾日志。
    2). 主數(shù)據(jù)庫日志。
    3). SQL語句日志。
    4). 臨時(shí)數(shù)據(jù)庫文件。
    5). 視圖和子查詢的臨時(shí)持久化文件。
    6). 臨時(shí)索引文件。
    7). VACUUM命令使用的臨時(shí)數(shù)據(jù)庫文件。
   
二、具體說明:

    1. 回滾日志:

    SQLite為了保證事物的原子性提交和回滾,在事物開始時(shí)創(chuàng)建了該臨時(shí)文件。此文件始終位于和數(shù)據(jù)庫文件相同的目錄下,其文件名格式為: 數(shù)據(jù)庫文件名 + "-journal"。換句話說,如果沒有該臨時(shí)文件的存在,當(dāng)程序運(yùn)行的系統(tǒng)出現(xiàn)任何故障時(shí),SQLite將無法保證事物的完整性,以及數(shù)據(jù)狀態(tài)的一致性。該文件在事物提交或回滾后將被立刻刪除。

    在事物運(yùn)行期間,如果當(dāng)前主機(jī)因電源故障而宕機(jī),而此時(shí)由于回滾日志文件已經(jīng)保存在磁盤上,那么當(dāng)下一次程序啟動(dòng)時(shí),SQLite在打開數(shù)據(jù)庫文件的過程中將會(huì)發(fā)現(xiàn)該臨時(shí)文件的存在,我們稱這種日志文件為"Hot Journal"。SQLite會(huì)在成功打開數(shù)據(jù)庫之前先基于該文件完成數(shù)據(jù)庫的恢復(fù)工作,以保證數(shù)據(jù)庫的數(shù)據(jù)回復(fù)到上一個(gè)事物開始之前的狀態(tài)。

    在SQLite中我們可以通過修改journal_mode pragma,而使SQLite對維護(hù)該文件采用不同的策略。缺省情況下該值為DELETE,即在事物結(jié)束后刪除日志文件。而PERSIST選項(xiàng)值將不會(huì)刪除日志文件,而是將回滾日志文件的頭部清零,從而避免了文件刪除所帶的磁盤開銷。再有就是OFF選項(xiàng)值,該值將指示SQLite在開始事物時(shí)不產(chǎn)生回滾日志文件,這樣一旦出現(xiàn)系統(tǒng)故障,SQLite也無法再保障數(shù)據(jù)庫數(shù)據(jù)的一致性。

    2. 主數(shù)據(jù)庫日志:

    在SQLite中,如果事物的操作作用于多個(gè)數(shù)據(jù)庫,即通過ATTACH命令附加到當(dāng)前連接中的數(shù)據(jù)庫,那么SQLite將生成主數(shù)據(jù)庫日志文件以保證事物產(chǎn)生的改變在多個(gè)數(shù)據(jù)庫之間保持原子性。和回滾日志文件一樣,主數(shù)據(jù)庫日志文件也位于當(dāng)前連接中主數(shù)據(jù)庫文件所處的目錄內(nèi),其文件名格式為:主數(shù)據(jù)庫文件名 + 隨機(jī)的后綴。在該文件中,將包含所有當(dāng)前事物將會(huì)改變的Attached數(shù)據(jù)庫的名字。在事物被提交之后,此文件亦被SQLite隨之刪除。

    主數(shù)據(jù)庫日志文件只有在某一事物同時(shí)操作多個(gè)數(shù)據(jù)庫時(shí)(主數(shù)據(jù)庫和Attached數(shù)據(jù)庫)才有可能被創(chuàng)建。通過該文件,SQLite可以實(shí)現(xiàn)跨多個(gè)數(shù)據(jù)庫的事物原子性,否則,只能簡單的保證每個(gè)單一的數(shù)據(jù)庫內(nèi)的狀態(tài)一致性。換句話說,如果該事物在執(zhí)行的過程中出現(xiàn)系統(tǒng)崩潰或主機(jī)宕機(jī)的現(xiàn)象,在進(jìn)行數(shù)據(jù)恢復(fù)時(shí),若沒有該文件的存在,將會(huì)導(dǎo)致部分SQLite數(shù)據(jù)庫處于提交狀態(tài),而另外一部分則處于回滾狀態(tài),因此該事物的一致性將被打破。

    3. SQL語句日志:

    在一個(gè)較大的事物中,SQLite為了保證部分?jǐn)?shù)據(jù)在出現(xiàn)錯(cuò)誤時(shí)可以被正?;貪L,所以在事物開始時(shí)創(chuàng)建了SQL語句日志文件。比如,update語句修改了前50條數(shù)據(jù),然而在修改第51條數(shù)據(jù)時(shí)發(fā)現(xiàn)該操作將會(huì)破壞某字段的唯一性約束,最終SQLite將不得不通過該日志文件回滾已經(jīng)修改的前50條數(shù)據(jù)。

    SQL語句日志文件只有在INSERT或UPDATE語句修改多行記錄時(shí)才有可能被創(chuàng)建,與此同時(shí),這些操作還極有可能會(huì)打破某些約束并引發(fā)異常。但是如果INSERT或UPDATE語句沒有被包含在BEGIN...COMMIT中,同時(shí)也沒有任何其它的SQL語句正在當(dāng)前的連接上運(yùn)行,在這種情況下,SQLite將不會(huì)創(chuàng)建SQL語句日志文件,而是簡單的通過回滾日志來完成部分?jǐn)?shù)據(jù)的UNDO操作。

    和上面兩種臨時(shí)文件不同的是,SQL語句日志文件并不一定要存儲(chǔ)在和數(shù)據(jù)庫文件相同的目錄下,其文件名也是隨機(jī)生成。該文件所占用的磁盤空間需要視UPDATE或INSERT語句將要修改的記錄數(shù)量而定。在事物結(jié)束后,該文件將被自動(dòng)刪除。

    4. 臨時(shí)數(shù)據(jù)庫文件:

    當(dāng)使用"CREATE TEMP TABLE"語法創(chuàng)建臨時(shí)數(shù)據(jù)表時(shí),該數(shù)據(jù)表僅在當(dāng)前連接內(nèi)可見,在當(dāng)前連接被關(guān)閉后,臨時(shí)表也隨之消失。然而在生命期內(nèi),臨時(shí)表將連同其相關(guān)的索引和視圖均會(huì)被存儲(chǔ)在一個(gè)臨時(shí)的數(shù)據(jù)庫文件之內(nèi)。該臨時(shí)文件是在第一次執(zhí)行"CREATE TEMP TABLE"時(shí)即被創(chuàng)建的,在當(dāng)前連接被關(guān)閉后,該文件亦將被自動(dòng)刪除。最后需要說明的是,臨時(shí)數(shù)據(jù)庫不能被執(zhí)行DETACH命令,同時(shí)也不能被其它進(jìn)程執(zhí)行ATTACH命令。
   
    5. 視圖和子查詢的臨時(shí)持久化文件:

    在很多包含子查詢的查詢中,SQLite的執(zhí)行器會(huì)將該查詢語句拆分為多個(gè)獨(dú)立的SQL語句,同時(shí)將子查詢的結(jié)果持久化到臨時(shí)文件中,之后在基于該臨時(shí)文件中的數(shù)據(jù)與外部查詢進(jìn)行關(guān)聯(lián),因此我們可以稱其為物化子查詢。通常而言,SQLite的優(yōu)化器會(huì)盡力避免子查詢的物化行為,但是在有些時(shí)候該操作是無法避免的。該臨時(shí)文件所占用的磁盤空間需要依賴子查詢檢索出的數(shù)據(jù)數(shù)量,在查詢結(jié)束后,該文件將被自動(dòng)刪除。見如下示例:
 

復(fù)制代碼 代碼如下:

    SELECT * FROM ex1 WHERE ex1.a IN (SELECT b FROM ex2);
 

    在上面的查詢語句中,子查詢SELECT b FROM ex2的結(jié)果將會(huì)被持久化到臨時(shí)文件中,外部查詢在運(yùn)行時(shí)將會(huì)為每一條記錄去檢查該臨時(shí)文件,以判斷當(dāng)前記錄是否出現(xiàn)在臨時(shí)文件中,如果是則輸出當(dāng)前記錄。顯而易見的是,以上的行為將會(huì)產(chǎn)生大量的IO操作,從而顯著的降低了查詢的執(zhí)行效率,為了避免臨時(shí)文件的生成,我們可以將上面的查詢語句改為:
 
復(fù)制代碼 代碼如下:

    SELECT * FROM ex1 WHERE EXISTS(SELECT 1 FROM ex2 WHERE ex2.b=ex1.a);
 

    對于如下查詢語句,如果SQLite不做任何智能的rewrite操作,該查詢中的子查詢也將會(huì)被持久化到臨時(shí)文件中,如:
 
復(fù)制代碼 代碼如下:

    SELECT * FROM ex1 JOIN (SELECT b FROM ex2) AS t ON t.b=ex1.a;
 

    在SQLite自動(dòng)將其修改為下面的寫法后,將不會(huì)再生成臨時(shí)文件了,如:
 
復(fù)制代碼 代碼如下:

    SELECT ex1.*, ex2.b FROM ex1 JOIN ex2 ON ex2.b=ex1.a;
 

    6. 臨時(shí)索引文件:
    當(dāng)查詢語句包含以下SQL從句時(shí),SQLite為存儲(chǔ)中間結(jié)果而創(chuàng)建了臨時(shí)索引文件,如:
    1). ORDER BY或GROUP BY從句。
    2). 聚集查詢中的DISTINCT關(guān)鍵字。
    3). 由UNION、EXCEPT和INTERSECT連接的多個(gè)SELECT查詢語句。
    需要說明的是,如果在指定的字段上已經(jīng)存在了索引,那么SQLite將不會(huì)再創(chuàng)建該臨時(shí)索引文件,而是通過直接遍歷索引來訪問數(shù)據(jù)并提取有用信息。如果沒有索引,則需要將排序的結(jié)果存儲(chǔ)在臨時(shí)索引文件中以供后用。該臨時(shí)文件所占用的磁盤空間需要依賴排序數(shù)據(jù)的數(shù)量,在查詢結(jié)束后,該文件被自動(dòng)刪除。

    7. VACUUM命令使用的臨時(shí)數(shù)據(jù)庫文件:
    VACUUM命令在工作時(shí)將會(huì)先創(chuàng)建一個(gè)臨時(shí)文件,然后再將重建的整個(gè)數(shù)據(jù)庫寫入到該臨時(shí)文件中。之后再將臨時(shí)文件中的內(nèi)容拷貝回原有的數(shù)據(jù)庫文件中,最后刪除該臨時(shí)文件。
    該臨時(shí)文件所占用的磁盤空間不會(huì)超過原有文件的尺寸。

三、相關(guān)的編譯時(shí)參數(shù)和指令:

    對于SQLite來說,回滾日志、主數(shù)據(jù)庫日志和SQL語句日志文件在需要的時(shí)候SQLite都會(huì)將它們寫入磁盤文件,但是對于其它類型的臨時(shí)文件,SQLite是可以將它們存放在內(nèi)存中以取代磁盤文件的,這樣在執(zhí)行的過程中就可以減少大量的IO操作了。要完成該優(yōu)化主要依賴于以下三個(gè)因素:

    1. 編譯時(shí)參數(shù)SQLITE_TEMP_STORE:

    該參數(shù)是源代碼中的宏定義(#define),其取值范圍是0到3(缺省值為1),見如下說明:
    1). 等于0時(shí),臨時(shí)文件總是存儲(chǔ)在磁盤上,而不會(huì)考慮temp_store pragma指令的設(shè)置。
    2). 等于1時(shí),臨時(shí)文件缺省存儲(chǔ)在磁盤上,但是該值可以被temp_store pragma指令覆蓋。
    3). 等于2時(shí),臨時(shí)文件缺省存儲(chǔ)在內(nèi)存中,但是該值可以被temp_store pragma指令覆蓋。
    4). 等于3時(shí),臨時(shí)文件總是存儲(chǔ)在內(nèi)存中,而不會(huì)考慮temp_store pragma指令的設(shè)置。
   
    2. 運(yùn)行時(shí)指令temp_store pragma:

    該指令的取值范圍是0到2(缺省值為0),在程序運(yùn)行時(shí)該指令可以被動(dòng)態(tài)的設(shè)置,見如下說明:
    1). 等于0時(shí),臨時(shí)文件的存儲(chǔ)行為完全由SQLITE_TEMP_STORE編譯期參數(shù)確定。
    2). 等于1時(shí),如果編譯期參數(shù)SQLITE_TEMP_STORE指定使用內(nèi)存存儲(chǔ)臨時(shí)文件,那么該指令將覆蓋這一行為,使用磁盤存儲(chǔ)。
    2). 等于2時(shí),如果編譯期參數(shù)SQLITE_TEMP_STORE指定使用磁盤存儲(chǔ)臨時(shí)文件,那么該指令將覆蓋這一行為,使用內(nèi)存存儲(chǔ)。
   
    3. 臨時(shí)文件的大?。?/p>

    對于以上兩個(gè)參數(shù),都有參數(shù)值表示缺省情況是存儲(chǔ)在內(nèi)存中的,只有當(dāng)臨時(shí)文件的大小超過一定的閾值后才會(huì)根據(jù)一定的算法,將部分?jǐn)?shù)據(jù)寫入到磁盤中,以免臨時(shí)文件占用過多的內(nèi)存而影響其它程序的執(zhí)行效率。
   
    最后在重新贅述一遍,SQLITE_TEMP_STORE編譯期參數(shù)和temp_store pragma運(yùn)行時(shí)指令只會(huì)影響除回滾日志和主數(shù)據(jù)庫日志之外的其它臨時(shí)文件的存儲(chǔ)策略。換句話說,回滾日志和主數(shù)據(jù)庫日志將總是將數(shù)據(jù)寫入磁盤,而不會(huì)關(guān)注以上兩個(gè)參數(shù)的值。

四、其它優(yōu)化策略:

    在SQLite中由于采用了Page Cache的緩沖優(yōu)化機(jī)制,因此即便臨時(shí)文件被指定存儲(chǔ)在磁盤上,也只有當(dāng)該文件的大小增長到一定的尺寸后才有可能被SQLite刷新到磁盤文件上,在此之前它們?nèi)詫Ⅰv留在內(nèi)存中。這就意味著對于大多數(shù)場景,如果臨時(shí)表和臨時(shí)索引的數(shù)據(jù)量相對較少,那么它們是不會(huì)被寫到磁盤中的,當(dāng)然也就不會(huì)有IO事件發(fā)生。只有當(dāng)它們增長到內(nèi)存不能容納的時(shí)候才會(huì)被刷新到磁盤文件中的。其中SQLITE_DEFAULT_TEMP_CACHE_SIZE編譯期參數(shù)可以用于指定臨時(shí)表和索引在占用多少Cache Page時(shí)才需要被刷新到磁盤文件,該參數(shù)的缺省值為500頁。

您可能感興趣的文章:
  • SQLite教程(一):SQLite數(shù)據(jù)庫介紹
  • SQLite教程(二):C/C++接口簡介
  • SQLite教程(三):數(shù)據(jù)表和視圖簡介
  • SQLite教程(四):內(nèi)置函數(shù)
  • SQLite教程(五):索引和數(shù)據(jù)分析/清理
  • SQLite教程(五):數(shù)據(jù)庫和事務(wù)
  • SQLite教程(六):表達(dá)式詳解
  • SQLite教程(七):數(shù)據(jù)類型詳解
  • SQLite教程(八):命令行工具介紹
  • SQLite教程(九):在線備份
  • SQLite教程(十):內(nèi)存數(shù)據(jù)庫和臨時(shí)數(shù)據(jù)庫

標(biāo)簽:衡水 湘潭 崇左 蘭州 銅川 仙桃 黃山 湖南

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《SQLite教程(十一):臨時(shí)文件》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    甘洛县| 镇康县| 稻城县| 壤塘县| 乐东| 垦利县| 天峨县| 文登市| 西乌| 虎林市| 桃园县| 庄河市| 彭泽县| 岳阳县| 丰城市| 天长市| 水城县| 宾川县| 漠河县| 军事| 犍为县| 九江市| 平武县| 安顺市| 阜城县| 伊春市| 德江县| 遂宁市| 冕宁县| 武隆县| 鄢陵县| 芜湖市| 文山县| 兴文县| 西藏| 鲜城| 清镇市| 得荣县| 远安县| 尚义县| 德昌县|