關于sqlite
sqlite是一款輕型的嵌入式的遵守acid的關系型數據庫管理系統,誕生已有15個年頭了。隨著移動互聯的發展,現在得到了更廣泛的使用。
在使用sqlite之前,我們勢必要先了解它一些“個性”的地方。下面是它的一些特點:
1、 自包含。sqlite很大層度上是獨立的,他只需要非常小的外部庫支持。任何程序能夠訪問磁盤就可以使用sqlite數據庫。這使它適用于嵌入式設備,缺乏桌面計算機支持的基礎設施。這也使得sqlite適用于不作任何修改就可運行在不同配置電腦上的程序。
2、 無服務器。大多數sql數據庫引擎被實現為一個單獨的服務器進程。程序要訪問數據庫與服務器通信使用某種形式的進程間通信(通常是tcp / ip),向服務器發送請求并接收返回結果。sqlite則不是這種工作方式。對于sqlite,想要訪問數據庫直接從磁盤上的對數據庫文件執行讀和寫操作。沒有中間的服務器進程。
3、 零配置。使用sqlite不需要“安裝”。沒有“設置”程序。沒有服務器進程需要啟動,停止,或配置。不需要管理員來創建一個新的數據庫實例或訪問權限分配給用戶。sqlite不使用配置文件。
4、 支持事務。事務數據庫的所有更改和查詢表現出原子性、一致性、隔離性、持久性(acid)。執行sqlite的事務操作時,要么完全執行,要么不執行,即使寫入磁盤的操作被程序崩潰,斷電等故障打斷。
5、 開源。和前面的特點相比,這個似乎沒有多大關系。之所以把它作為一個特點,是因為開源在很大層度上會成為我們選擇一個解決方案的重要維度。
本文主要介紹的是關于c# sqlite執行效率優化的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧
一、如要使用sqlite,可以從visual studio中的“程序包管理器控制臺”輸入以下命令完成安裝:
pm> install-package system.data.sqlite.core
sqlite則會安裝到項目中,支持32位或64位,如下圖所示:
二、新建一個sqlite數據庫,名稱命名為test.db,其表名稱及列定義如下:
三、新建一個控制臺應用的解決方案,并輸入以下代碼,看看sqlite的執行時間:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
using system; using system.collections.generic; using system.data; using system.data.sqlite; using system.diagnostics; namespace consoleapp { class program { static void main( string [] args) { sqliteconnection connection = run(() => new sqliteconnection( "data source = test.db" ), "連接對象初始化" ); run(() => connection.open(), "打開連接" ); sqlitecommand command = run(() => new sqlitecommand(connection), "命令對象初始化" ); run(() => { command.commandtext = $ "delete from info;vacuum;update sqlite_sequence set seq ='0' where name ='info';" ; command.executenonquery(); }, "執行delete命令及收縮數據庫" ); run(() => { for ( int i = 0; i < 3000; i++) { command.commandtext = $ "insert into info(name, age) values ('a{i:000}','{i}')" ; command.executenonquery(); } command.executescalar(); }, "[---使用事務---]事務執行insert命令" ); list<test> list1 = run(() => { command.commandtext = $ "select * from info" ; list<test> tests = new list<test>(); sqlitedatareader reader = command.executereader(); while (reader.read()) { test t = new test { id = ( long )reader[0], name = ( string )reader[1], age = ( long )reader[2] }; tests.add(t); } reader.close(); return tests; }, "[---不使用事務---]使用executereader方式執行select命令" ); datatable table1 = run(() => { command.commandtext = $ "select * from info" ; sqlitedataadapter adapter = new sqlitedataadapter(command); datatable _table = new datatable(); adapter.fill(_table); return _table; }, "[---不使用事務---]使用fill table方式執行select命令" ); run(() => { command.commandtext = $ "delete from info;vacuum;update sqlite_sequence set seq ='0' where name ='info';" ; command.executenonquery(); }, "執行delete命令及收縮數據庫" ); sqlitetransaction transaction = run(() => connection.begintransaction(), "開始事務" ); run(() => { for ( int i = 0; i < 3000; i++) { command.commandtext = $ "insert into info(name, age) values ('a{i:000}','{i}')" ; command.executenonquery(); } var result = command.executescalar(); }, "[---使用事務---]執行insert命令" ); list<test> list2 = run(() => { command.commandtext = $ "select * from info" ; list<test> tests = new list<test>(); sqlitedatareader reader = command.executereader(); while (reader.read()) { test t = new test { id = ( long )reader[0], name = ( string )reader[1], age = ( long )reader[2] }; tests.add(t); } reader.close(); return tests; }, "[---使用事務---]使用executereader方式執行select命令" ); datatable table2 = run(() => { command.commandtext = $ "select * from info" ; sqlitedataadapter adapter = new sqlitedataadapter(command); datatable _table = new datatable(); adapter.fill(_table); return _table; }, "[---使用事務---]使用fill table方式執行select命令" ); run(() => transaction.commit(), "提交事務" ); run(() => connection.close(), "關閉連接" ); console.readkey(); } public static void run(action action, string description) { stopwatch sw = stopwatch.startnew(); action(); console.writeline($ "--> {description}: {sw.elapsedmilliseconds}ms" ); } public static t run<t>(func<t> func, string description) { stopwatch sw = stopwatch.startnew(); t result = func(); console.writeline($ "--> {description}: {sw.elapsedmilliseconds}ms" ); return result; } } class test { public long id { set ; get ; } public string name { set ; get ; } public long age { set ; get ; } } } |
程序運行結果如下:
四、根據以上的程序運行結果,可以得出以下結論:
1)sqliteconnection對象初始化、打開及關閉,其花費時間約為109ms,因此,最好不要頻繁地將該對象初始化、打開與關閉,這與sql server不一樣,在這里建議使用單例模式來初始化sqliteconnection對象;
在網上查找了sqlitehelper幫助類,但很多都是沒執行一次sql語句,都是使用這樣的流程:初始化連接對象->打開連接對象->執行命令->關閉連接對象,如下的代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public int executenonquery( string sql, params sqliteparameter[] parameters) { int affectedrows = 0; using (sqliteconnection connection = new sqliteconnection(connectionstring)) { using (sqlitecommand command = new sqlitecommand(connection)) { try { connection.open(); command.commandtext = sql; if (parameters.length != 0) { command.parameters.addrange(parameters); } affectedrows = command.executenonquery(); } catch (exception) { throw ; } } } return affectedrows; } |
根據以上的結論,如果要求執行時間比較快的話,這樣的編寫代碼方式實在行不通。
2)使用executereader方式比使用adapter fill table方式快一點點,但這不是絕對的,這取決于編寫的代碼;
3)無論是執行插入或查詢操作,使用事務比不使用事務快,尤其是在批量插入操作時,減少得時間非常明顯;
比如在不使用事務的情況下插入3000條記錄,執行所花費的時間為17.252s,而使用事務,執行時間只用了0.057s,效果非常明顯,而sql server不存在這樣的問題。
4)不能每次執行一條sql語句前開始事務并在sql語句執行之后提交事務,這樣的執行效率同樣是很慢,最好的情況下,是在開始事務后批量執行sql語句,再提交事務,這樣的效率是最高的。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.cnblogs.com/cncc/p/9121874.html