sqlite 数据库性能调优

时间:2022-09-18 10:34:59


一 、完整性检查


   完整性检查 ,是保障 数据库可用 ,app可用的 ,程序启动后,优先要做的事情

      

   数据库损坏的表现: “database disk image is malformed”


  1 检查方式:

         

      (1) PRAGMA schema.integrity_check; 

        (2) PRAGMA schema.quick_check; 

        (3) select name from sqlite_master where type=‘table'

                   select 1 from %@ limit 1


  2 比较:

(1)integrity_check


 out-of-order records(乱序的记录)

 missing pages(缺页)

 malformed records(错误的记录)

 missing index entries(丢失的索引)

 UNIQUE constraint(唯一性约束)

 NOT NULL (非空约束)

耗时较多。


(2) quick_check

  

   不检查约束条件

   不检查对索引内容与表内容匹配的校验

   耗时较短

 

(3)是一种不太靠谱的方式,只检查库中的表是否存在,表的部分数据正确与否。


耗时最短。 



(4)从耗时的角度来看:

    

 与库中的数据量 有很大关系

 当库中的数据量 <  10000 量级时 ,没啥区别。

 当达到 100000 时, 第三种的速度明显快很多。

  50万 数量级 时,效率是(1)与(2)的100倍。



  二、 影响数据性能的参数:

      

     1 底层 page_size ,table_size,cache_size

     

      在内存允许的情况下增加 page_size 和 cache_size 能够获得更快的查询速度。但过大的 page_size 也会造成 B-Tree 查询退化到二分查找、CPU 占用增加以及 OS 级 cache 命中率的下降的问题。


     通过反复比较测试不同组合的 page_size、cache_size、table_size、存储的数据类型以及各种可能的增删查改比例,我们发现后三者都是引起 page_size 和 cache_size 性能波动的因素。也就是说对于不同的数据库并不存在普遍适用的 page_size 和 cache_size 能一劳永逸的帮我们解决问题。

 

 

     2  使用事物 与 非事物,索引。


         批量更新数据的场景,使用数据库事务,批量更新数据是非常快的。


      3  缓存被编译后的 SQL 语句


       数据库使用的 SQL 语句也需要经过编译后才能被执行使用。SQL 语句的编译结果如果能够被缓存下来,第二次及以后再被使用时就能直接利用缓存结果,大大减少整个操作的执行时间。


      4 Full Text Search(FTS)


      5 .磁盘同步

PRAGMA synchronous;

 

 

PRAGMA synchronous = FULL; (2) 

PRAGMA synchronous = NORMAL; (1) 

PRAGMA synchronous = OFF; (0)

 

   当synchronous设置为FULL 

   SQLite数据库引擎在紧急时刻会暂停以确定  数据已经写入磁盘。这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。 在SQLite 3中修改为FULL。



   当synchronous设置为NORMAL

   SQLite数据库引擎在大部分紧急时刻会暂停,但不像FULL模式下那么频繁。 NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。但实际上,在这种情况 下很可能你的硬盘已经不能使用,或者发生了其他的不可恢复的硬件错误。在SQLite 2中,缺省值为NORMAL.


   设置为synchronous OFF 

   SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃, 数据不会损伤,但在系统崩溃或写入数据时意外断电的情况下数据库可能会损坏。另一方面,在synchronous OFF时 一些操作可能会快50倍甚至更多。



     数据安全性不高的场景,可以考虑更改 syncchronous = off 的模式;(写数据的速度50倍+的提升)

     数据安全性较高的场景,可以考虑更改 syncchronous = nomal 的模式;(写数据的性能也有5倍+的提升)


 

   6  内存模式 

PRAGMA temp_store = DEFAULT; (0) 

PRAGMA temp_store = FILE; (1) 

PRAGMA temp_store = MEMORY; (2)


当temp_store设置为DEFAULT (0),使用编译时的C预处理宏 TEMP_STORE来定义储存临时表和临时索引的位置。 

当设置为FILE (1),则存放于文件中。temp_store_directory pragma 可用于指定存放该文件的目录。 

当设置为MEMORY (2),临时表和索引则存放于内存中。 

当改变temp_store设置,所有已存在的临时表,索引,触发器及视图将被立即删除。 

   


7  数据库加密

  SQLite 数据库加密对性能的损耗按照官方文档的评测大约在3%的 CPU 时间。  加密算法对性能的影响。


 

8  WAL 与 DEL 

 默认的是del ,




       读写操作时,DEL模式要处理各种锁。 

       写操作是独享的,写阻塞读。

      读完成的时候才能写,读阻塞写。




      数据由1万增加到2万。读100条的时候写10条,写10条数据所耗时间 。

WAL模式所耗时间为DEL模式所耗时间的1/4。



        数据由1万增加到2万。读100条的时候写10条。读100,数据所耗时间。

      DEL模式所耗时间略高于WAL模式所耗时间.时间越长次数越多,WAL效率越高


       WAL模式下要更进一步提升性能的话,可以考虑改变 checkpoint。

      我们在把  checkpoint 改成了10000(默认是1000),checkpoint = 1000 是 日志文件 1M 的时候回写到数据库,改成 10000 就变成了 日志文件 10M 时回写数据到数据库。 demo测试性能,有2倍+的提升。






9  分库与分表



        (1)随着表中数据量的减少,查询的相同数量数据的时间逐渐减少。


       例如有与100个人的聊天记录,分表后,每打开一个会话时,读数据时,对应的表的规模是分表前的 1/100。查询速度必然增加。写数据时也是如此。



        (2)在设计数据库时,我们会把一个对象的属性分成不同的列按行存储。如果属性是个数量不定的数组,切忌不要把这个数组属性放到一个新表里面。上面我们提到过数据操作最耗时的其实是访问外存上面的数据。当数据量很大时,多张表的外存访问是非常慢的。这里的做法是讲数组数据用 JSON 序列化后,已 VARCHAR 或者 BLOB 的形式存成一列,和其他的数据放在同一个数据表当中。



10 mmap优化


mmap对I/O性能的提升无需赘言,尤其是对于读操作。SQLite也在OS层封装了mmap的接口,可以无缝地切换mmap和普通的I/O接口。只需配置PRAGMA mmap_size=XXX即可开启mmap。 



参考:

http://www.trinea.cn/android/database-performance/

http://www.cocoachina.com/ios/20161109/18030.html

http://geek.csdn.net/news/detail/96248

http://blog.163.com/niuxiangshan@126/blog/static/170596595201221411454090/