设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 重新 试卷 创业者
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

Sqlite事务模型、性能优化Tips、常见误区(4)

发布时间:2019-09-26 10:09 所属栏目:21 来源:hamsongliu
导读:2.4.1 结论 多线程设置是决定DDL、DML、WAL(包括SHM)操作是否线程安全的设置 多线程设置与读写(连接)分离没有任何关系,并不是实现读写(连接)分离的必要条件(很多人对这一点有误解) 3,性能优化tips 3.1 合理使用事

2.4.1 结论

  • 多线程设置是决定DDL、DML、WAL(包括SHM)操作是否线程安全的设置
  • 多线程设置与读写(连接)分离没有任何关系,并不是实现读写(连接)分离的必要条件(很多人对这一点有误解)

3,性能优化tips

3.1 合理使用事务

由#2.2的分析可知,写操作会在RESERVED状态下将数据更改、b-tree的更改、日志等写入page cache,并最终flush到数据库文件中;使用事务的话,只需要一次对DB文件的flush操作,同时也不会对其他连接的读写操作阻塞;对比以下两种数据写入方式(这里以统一存储提供的API为例),实测耗时有十几倍的差距(当然对于频繁的读操作,使用事务可以减事务状态的切换,也会有一点点性能提升):

  1. // batch insert in transaction with 1000000 records 
  2. // 
  3. AliDBExecResult* execResult = NULL; 
  4. _database->InTransaction([&]() -> bool {    // in transaction 
  5.   auto statement = _database->PrepareStatement("INSERT INTO table VALUES(?, ?)"); 
  6.   for (auto record : records) {    // bind 1000000 records 
  7.     // bind record 
  8.     ... 
  9.     ... 
  10.     statement->AddBatch(); 
  11.   } 
  12.   auto result = statement->ExecuteUpdate(); 
  13.   return result->is_success_; 
  14. }); 
  15.  
  16.  
  17. // batch insert with 1000000 records, no transaction 
  18. // 
  19. auto statement = _database->PrepareStatement("INSERT INTO table VALUES(?, ?)"); 
  20. for (auto record : records) {    // bind 1000000 records 
  21.   // bind record 
  22.   ... 
  23.   ... 
  24.   statement->ExecuteUpdate(); 

3.2 启用WAL + 读写(连接)分离

启用WAL之后,数据库大部分写操作变成了串行写(对WAL文件的串行操作),对写入性能提升有非常大的帮助;同时读写操作可以互相完全不阻塞(如#2.3所述)。上述两点比较好的解释了启用WAL带来的提升;同时推荐一个写连接 + 多个读连接的模型,如下图所示:

sqlite事务模型、性能优化tips、常见误区

3.2.1 读写连接分离的细节

  • 读操作使用不同的连接并发执行,可以完全避免由于显式事务、写操作之间的锁竞争带来的死锁
  • 所有的写操作、显式事务操作都使用同一个连接,且所有的写操作、显式事务操作都串行执行

可以完全避免由于显式事务、写操作之间的锁竞争带来的死锁,如#2.2.1提到的死锁的例子

并发写并不能有效的提高写入效率,参考如下伪代码,哪段执行更快?

  1. // two transactions:  
  2. void Transaction_1() { 
  3.         connection_->Exec("BEGIN"); 
  4.       connection_->Exec("insert into table(value) values('xxxx')"); 
  5.       connection_->Exec("COMMIT"); 
  6.  
  7. void Transaction_2() { 
  8.         connection_->Exec("BEGIN"); 
  9.       connection_->Exec("insert into table(value) values('xxxx')"); 
  10.       connection_->Exec("COMMIT"); 
  11.  
  12. // code fragment 1: concurrent transaction 
  13. thread1.RunBlock([]() -> void { 
  14.       for (int i=0; i< 100000; i++) { 
  15.             Transaction_1(); 
  16.     } 
  17. }); 
  18.  
  19. thread2.RunBlock([]() -> void { 
  20.       for (int i=0; i< 100000; i++) { 
  21.             Transaction_2(); 
  22.     } 
  23. }); 
  24.  
  25. thread1.Join(); thread2.join(); 
  26.  
  27. // code fragment 2: serial transaction 
  28. for (int i=0; i< 100000; i++) { 
  29.   Transaction_1(); 
  30. for (int i=0; i< 100000; i++) { 
  31.   Transaction_2(); 

3.3 针对具体业务场景,设置合适的WAL SIZE

如#2.3提到,过大的WAL文件,会让查找操作从B-Tree查找退化成线性查找(WAL中page连续存储);但大的WAL文件对写操作较友好。对于大记录的写入操作,较大的wal size会有效提高写入效率,同时不会影响查询效率

3.4 针对业务场景分库分表

分库分表可以有效提高数据操作的并发度;但同时过多的表会影响数据库文件的加载速度。现在数据库方向的很多研究包括Auto sharding, paxos consensus, 存储和计算的分离等;Auto

application-awared optimization,Auto hardware-awared optimization,machine

learning based optimization也是不错的方向。

3.5 其他

包括WAL checkpoint策略、WAL size优化、page size优化等,均需要根据具体的业务场景设置。

4,常见问题 & 误区

4.1 线程安全设置及误区

sqlites configuration options: https://sqlite.org/c3ref/c_config_getmalloc.html

按照sqlite文档,sqlite线程安全模式有以下三种:

SQLITE_CONFIG_SINGLETHREAD(单线程模式)

This option sets the threading mode to Single-thread. In other words, it disables all mutexing and puts SQLite into a mode where it can only be used by a single thread.

SQLITE_CONFIG_MULTITHREAD(多线程模式)

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读