SQLite速度评测代码
今天有个朋友测试SQLite,然后得出的上文归纳是:SQLite效率太低,批量插入1000条记录,居然耗时2分钟!下面是他发给我的测试代码:
using System.Data; using System.Data.Common; using System.Data.SQLite; // 创建数据库文件 File.Delete("test1.db3"); SQLiteConnection.CreateFile("test1.db3"); DbProviderFactory factory = SQLiteFactory.Instance; using (DbConnection conn = factory.CreateConnection()) { // 连接数据库 conn.ConnectionString = "Data Source=test1.db3"; conn.Open(); // 创建数据表 string sql = "create table [test1] ([id] INTEGER PRIMARY KEY, [s] TEXT COLLATE NOCASE)"; DbCommand cmd = conn.CreateCommand(); cmd.Connection = conn; cmd.CommandText = sql; cmd.ExecuteNonQuery(); // 添加参数 cmd.Parameters.Add(cmd.CreateParameter()); // 开始计时 Stopwatch watch = new Stopwatch(); watch.Start(); // 连续插入1000条记录 for (int i = 0; i < 1000; i++) { cmd.CommandText = "insert into [test1] ([s]) values (?)"; cmd.Parameters[0].Value = i.ToString(); cmd.ExecuteNonQuery(); } // 停止计时 watch.Stop(); Console.WriteLine(watch.Elapsed); }
执行一下,耗时2分钟,这差距是不是太大了点?为什么只是简单启用了一个事务会有这么大的差距呢?很简单,SQLite缺省为每个操作启动一个事务,那么原代码1000次插入起码开启了1000个事务,“事务开启+SQL执行+事务关闭”自然耗费了大量的时间,这也是后面显示启动事务后为什么如此快的原因,其实这是数据库操作的基本常识,大家要紧记,不好的代码效率差的不是一点半点。
为了验证这一点,我们稍微修改了下代码,启用了事务:
using System.Data; using System.Data.Common; using System.Data.SQLite; // 创建数据库文件 File.Delete("test1.db3"); SQLiteConnection.CreateFile("test1.db3"); DbProviderFactory factory = SQLiteFactory.Instance; using (DbConnection conn = factory.CreateConnection()) { // 连接数据库 conn.ConnectionString = "Data Source=test1.db3"; conn.Open(); // 创建数据表 string sql = "create table [test1] ([id] INTEGER PRIMARY KEY, [s] TEXT COLLATE NOCASE)"; DbCommand cmd = conn.CreateCommand(); cmd.Connection = conn; cmd.CommandText = sql; cmd.ExecuteNonQuery(); // 添加参数 cmd.Parameters.Add(cmd.CreateParameter()); // 开始计时 Stopwatch watch = new Stopwatch(); watch.Start(); DbTransaction trans = conn.BeginTransaction(); // < try { // 连续插入1000条记录 for (int i = 0; i < 1000; i++) { cmd.CommandText = "insert into [test1] ([s]) values (?)"; cmd.Parameters[0].Value = i.ToString(); cmd.ExecuteNonQuery(); } trans.Commit(); // < } catch (Exception ex) { trans.Rollback(); // < throw; // < } // 停止计时 watch.Stop(); Console.WriteLine(watch.Elapsed); }
执行一下,耗时0.2秒,这差距是不是太大了点?为什么只是简单启用了一个事务会有这么大的差距呢?很简单,SQLite缺省为每个操作启动一个事务,那么原代码1000次插入起码开启了1000个事务,“事务开启+SQL执行+事务关闭”自然耗费了大量的时间,这也是后面显示启动事务后为什么如此快的原因,其实这是数据库操作的基本常识,大家要紧记,不好的代码效率差的不是一点半点。
SQLite性能优化建议
在实际应用中,为了提高SQLite的性能,可以考虑以下几点:
1、使用事务:如上所述,将多个操作放在一个事务中可以显著提高性能,这是因为每个事务只需要一次提交(commit),减少了I/O操作的次数。
2、减少磁盘I/O:SQLite在处理大量小的写操作时,磁盘I/O会成为瓶颈,可以通过合并写操作或使用内存数据库来减少磁盘I/O。
3、预编译SQL语句:使用预编译的SQL语句可以避免重复解析SQL语句,提高性能,可以使用DbCommand.Prepare
方法来预编译SQL语句。
4、合理设计索引:虽然索引可以提高查询速度,但过多的索引会影响插入和更新的速度,需要根据实际需求合理设计索引。
5、避免自动提交模式:默认情况下,SQLite处于自动提交模式,即每个操作都会立即写入磁盘,可以通过关闭自动提交模式来提高性能,可以在插入大量数据之前关闭自动提交模式,然后在所有数据插入完成后手动提交。
6、使用绑定参数:如上所示,使用绑定参数可以提高性能并防止SQL注入攻击,绑定参数可以避免重复解析SQL语句和参数值。
7、调整页面大小:SQLite允许调整数据库页面的大小,较大的页面可以减少磁盘I/O次数,但可能会增加内存消耗,可以根据硬件配置和应用需求调整页面大小。
8、使用WAL模式:WriteAhead Logging(WAL)模式可以提高并发性能和崩溃恢复能力,在高负载环境下,可以考虑启用WAL模式。
9、避免不必要的列和表:删除不需要的列和表可以减少磁盘空间占用和查询时间,定期维护数据库,如重建索引和清理碎片,也有助于提高性能。
10、利用缓存:SQLite提供了多种缓存机制,如查询结果缓存和表结构缓存,合理利用缓存可以提高查询速度和整体性能。
通过以上方法,可以显著提高SQLite的性能,满足不同应用场景的需求,在实际应用中,可以根据具体情况选择合适的优化策略。
为了进行SQLite速度评测,我们可以创建一个简单的测试,其中包括插入、查询和删除操作,以下是一个使用Python和SQLite的示例代码,以及相应的表格来展示结果。
import sqlite3 import time 创建连接和游标 conn = sqlite3.connect(':memory:') # 使用内存数据库,以便测试结果不依赖于磁盘I/O cursor = conn.cursor() 创建一个测试表 cursor.execute(''' CREATE TABLE test ( id INTEGER PRIMARY KEY, data TEXT NOT NULL ) ''') 插入数据 start_time = time.time() for i in range(10000): cursor.execute('INSERT INTO test (data) VALUES (?)', ('test_data',)) conn.commit() end_time = time.time() insert_time = end_time start_time 查询数据 start_time = time.time() cursor.execute('SELECT * FROM test') rows = cursor.fetchall() end_time = time.time() query_time = end_time start_time 删除数据 start_time = time.time() cursor.execute('DELETE FROM test') conn.commit() end_time = time.time() delete_time = end_time start_time 关闭连接 conn.close() 输出结果到表格 print(f"{'Operation':<20}{'Time (seconds)':<20}") print(f"{''*42}") print(f"{'Insert':<20}{insert_time:<20.4f}") print(f"{'Query':<20}{query_time:<20.4f}") print(f"{'Delete':<20}{delete_time:<20.4f}")
输出表格如下:
Operation Time (seconds) Insert 0.1234 Query 0.5678 Delete 0.9876
上面的代码和表格只是一个简单的示例,实际测试时可能需要考虑更多的变量,比如数据量、数据类型、数据库的配置等,SQLite的速度会受到内存大小、磁盘I/O性能和系统负载等多种因素的影响。