一、可优化的切入点
1 使用事务 (已用)
本质:减少数据库的 open 和 close,减少文件的反复打开读写关闭
事务的实现是依赖 sqlite 运行时产生的临时文件,借助这个临时文件来完成原子操作和回滚功能。既然属于文件,就符合Unix的文件范型(Open-Read/Write- Close),因而对于批量的修改操作会出现反复打开文件读写再关闭的操作。
2 使用索引 (未用)
索引,使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。
在表中建立索引,然后在索引中找到符合查询条件的索引值,快速找到表中对应的记录。
Create Index ’index_name’ On ’table_name’;
对于增加,更新和删除来说,使用了索引会变慢;
建立索引会增加数据库的大小,为数据量比较小的表建立索引,往往会事倍功半。
所以,使用索引需要考虑实际情况进行利弊权衡,对于查询操作量级较大,业务对要求查询要求较高的,还是推荐使用索引的。
3 使用预编译SQL语句(已用)
Sqlite执行需要将程序中的sql语句编译成对应的SQLiteStatement
比如:select * from ,被执行100次就需要编译100次。
对于批量处理插入或者更新的操作,我们可以使用显示编译来做到重用SQLiteStatement。
4 使用异步操作(已用)
数据库的操作,属于本地IO,通常比较耗时,如果处理不好,很容易导致卡顿,因此建议将这些耗时操作放入异步线程中处理。
5 内存模式 (未用)
以空间换时间
(1)内存数据库:
在SQLite中,数据库通常是存储在磁盘文件中的。然而在有些情况下,我们可以让数据库始终驻留在内存中。最常用的一种方式是在调用sqlite3_open()的时候,数据库文件名参数传递":memory:",如:
rc = sqlite3_open(":memory:", &db) ;
在调用完以上函数后,不会有任何磁盘文件被生成,取而代之的是,一个新的数据库在纯内存中被成功创建了。由于没有持久化,该数据库在当前数据库连接被关闭后就会立刻消失。需要注意的是,尽管多个数据库连接都可以通过上面的方法创建内存数据库,然而它们却是不同的数据库,相互之间没有任何关系。事实上,我们也可以通过Attach命令将内存数据库像其他普通数据库一样,附加到当前的连接中,如:
ATTACH DATABASE ':memory:' AS aux1 ;
(2)临时数据库:
在调用sqlite3_open()函数或执行ATTACH命令时,如果数据库文件参数传的是空字符串,那么一个新的临时文件将被创建作为临时数据库的底层文件,如:
rc = sqlite3_open("", &db);
或
ATTACH DATABASE '' AS aux2;
和内存数据库非常相似,两个数据库连接创建的临时数据库也是各自独立的,在连接关闭后,临时数据库将自动消失,其底层文件也将被自动删除。
尽管磁盘文件被创建用于存储临时数据库中的数据信息,但是实际上临时数据库也会和内存数据库一样通常驻留在内存中,唯一不同的是,当临时数据库中数据量过大时,SQLite为了保证有更多的内存可用于其它操作,因此会将临时数据库中的部分数据写到磁盘文件中,而内存数据库则始终会将数据存放在内存中。
6 WAL 与 DEL (已用)
(1)默认的是DEL ,读写操作时,DEL模式要处理各种锁。 写操作是独享的,写阻塞读。读完成的时候才能写,读阻塞写。
数据由1万增加到2万。读100条的时候写10条,写10条数据所耗时间 。
WAL模式所耗时间为DEL模式所耗时间的1/4。
数据由1万增加到2万。读100条的时候写10条。读100条数据所耗时间。
DEL模式所耗时间略高于WAL模式所耗时间。时间越长次数越多,WAL效率越高。
(2) WAL模式下要更进一步提升性能的话,可以考虑改变 checkpoint。
当然WAL模式也有一些缺点:
· 当每个事务数据量比较大时,接近或超过1000页的数据量时,会导致WAL内容频繁同步至实际数据库文件,导致性能下降。
我们在把 checkpoint 改成了10000(默认是1000),checkpoint = 1000 是日志文件 1M 的时候回写到数据库,改成 10000 就变成了 日志文件 10M 时回写数据到数据库。有2倍+的提升。
7 分库与分表(偏业务层面)(已用)
(1) 随着表中数据量的减少,查询的相同数量数据的时间逐渐减少。
例如有与100个人的聊天记录,分表后,每打开一个会话时,读数据时,对应的表的规模是分表前的 1/100。查询速度必然增加。写数据时也是如此。
(2)在设计数据库时,我们会把一个对象的属性分成不同的列按行存储。如果属性是个数量不定的数组,切忌不要把这个数组属性放到一个新表里面。上面我们提到过数据操作最耗时的其实是访问外存上面的数据。当数据量很大时,多张表的外存访问是非常慢的。这里的做法是讲数组数据用 JSON 序列化后,已 VARCHAR 或者 BLOB 的形式存成一列,和其他的数据放在同一个数据表当中。
8 mmap优化 (未用)
mmap对I/O性能的提升无需赘言,尤其是对于读操作。SQLite也在OS层封装了mmap的接口,可以无缝地切换mmap和普通的I/O接口。只需配置
PRAGMA mmap_size = XXX
即可开启mmap。
理论上mmap方式能减少内核和用户空间的IO,但在iOS系统中,影响并不大。
二、测试对比
参考:www.xxxxxxxxx
网友评论