背景
-
由于开发的软件,需要频繁的访问数据库,且数据库很大。15W条数据(表有20个列),且需要横跨3张表进行查询。速度很慢,急迫的需要进行性能优化。
我们列出了可行的方案:1:程序进行缓存 2:基于已有的SQLite进行查询和插入速度优化 3:寻找一个开源的数据缓存框架
经过一段时间的研究,决定尝试SQLite 内存数据库来提高查询和插入速度,并且把目前使用的SQlite替换SQLite-net 封装的底层库,大致方向确定了。
集成项目需要考虑的点
通过验证文件数据库和内存数据库的比较,内存数据库速度达到了预期。接下来,需要确定集体方案和细节问题,集成到项目需要考虑如下几个问题:
1:内存数据库和文件数据库相互转换速度问题
2:目前项目怎么让其改动最小,把这次改动的风险降到最低
3:内存数据库的数据怎么落地
4:怎么防止程序中途挂掉,造成内存数据库数据丢失。
实践细节问题
-
目前项目访问了一个数据库并且建立了常链接,由于内存数据库是放到内存的,而且需要加载和写回,所以只想把数据库数据量大的表放到内存数据库(内存数据库只存放一张表的数据),而不是全部表都放内存数据库。
-
这样以来,程序就会存在2个数据库链接。对于业务是不友好的。如果涉及到有一些业务需要访问内存数据库,有一些业务又要访问文件数据库。所有入口就需要进行修改。工程量太大,是个体力活。那怎么把内存数据库和文件数据库视为一个数据库,业务不用感知任何链接库的区分。对于业务来说只有一个数据库链接库是最好的。=
-
那么基于这样的一个背景对SQLite 内存数据库和文件数据库使用的场景进行研究,这样的场景可以用
SQLITE ATTACH
把文件数据库附加到内存数据库。这样内存数据库拥有了所有的表结构。把目前项目的链接这直接替换为内存数据库。业务什么都不用修改…美滋滋啊! -
但是一想,如果这样附加的话,那内存数据库不是就有2张一模一样的表了吗(因为文件数据库有一张表比如“Student”,内存数据库也有一张表“Student”)? 那这种情况我其实是想操作的是内存数据的“Student”表。然后进行了一番研究,查阅了腾讯云的开发社区找到一段对此场景的描述:
可以使用语法 schema-name.table-name 引用附加数据库中的表。如果表的名称在所有连接的数据库以及主数据库和临时数据库中都是唯一的,则不需要模式名称前缀。如果不同数据库中的两个或更多表具有相同的名称,并且未在表引用上使用模式名称前缀,则所选的表是数据库中最近连接的表。
这个问题也得到了解决,可以通过别名,或者链接库的先后顺序来控制,访问的哪一张表。
内存数据量落地
内存数据库的加载和落地,目前大概的实现思路:
* 程序登录,异步线程把表数据导入内存数据库
* 退出时,直接把文件数据库对应的表进行删除,新创建一张表(不创建索引)。然后导入内存数据库的数据完毕后在创建表索引
* 对于中途异常退出,导致的内存数据库数据丢失的问题。这个目前软件做的比较好,天然支持…(数据产生时,很及时的发送了MQ消息告诉了云端和其他客户端)。所以面对程序非正常退出的场景,程序登录的时候会去云端获取全部数据。