乐趣区

关于java:微信为什么使用-SQLite-保存聊天记录

SQLite 是一个被大家低估的数据库,但有些人认为它是一个不适宜生产环境应用的玩具数据库。事实上,SQLite 是一个十分牢靠的数据库,它能够解决 TB 级的数据,但它没有网络层。接下来,本文将与大家独特探讨 SQLite 在过来一年中最新的 SQL 性能。

SQLite“只是”一个库,它不是传统意义上的服务器。因而,在某些场合下,它的确不适合。然而,在相当多的其余场合,它却是最合适的抉择。SQLite 号称是部署和应用最宽泛的数据库引擎。我认为这很有可能,因为 SQLite 没有版权的限度。无论何时,只有开发者想应用 SQL 在文件中存储结构化的数据,SQLite 应是首选计划。

SQLite 的 SQL 方言也十分弱小。它比 MySQL 早四年就开始反对 with 语句。最近,它还实现了对于窗口函数的反对,这仅仅比 MySQL 晚五个月。

接下来,本文将介绍 SQLite 在 2018 年新减少的 SQL 性能,也就是 SQLite 从版本 3.22.0 到 3.26.0 所新减少的 SQL 性能。

具体内容包含:

    1. 布尔字面量和判断
    1. 窗口函数
    1. Filter 子句
    1. Insert … on conflict (“Upsert”)
    1. 重命名列
    1. 在 Modern-SQL.com 上接下来

布尔变量和判断

SQLite 反对“假”布尔值:它承受 Boolean 作为类型的名称,但它将其当作整数对待(这一点十分相似于 MySQL)。真值 true 和 false 别离由数值 1 和 0 示意(这一点和 C 语言一样)。

从版本 3.23.0 开始,SQLite 将关键字 true 和 false 别离用数字 1 和 0 示意,并反对 is [not] true | false 的判断语句。当初,它不再反对关键字 unknown。开发者能够应用空值 null 来代替,因为 unknown 和 null 的布尔值是一样的。

在 INSERT 和 UPDATE 语句中,字面量 true 和 false 能够大大提高 values 和 set 子句的可读性。

is [not] true | false 这个判断语句很有用,它与比拟操作的含意不一样:

咱们来比拟一下

WHERE c <> FALSE 

WHERE c IS NOT FALSE

在下面的例子中,如果 c 是 null, 那么 c <> false 的后果是 unknown.

这是因为 WHERE 子句只承受后果为 true 的值,它会过滤掉后果为 false 或 unknown 的值。这样,它就会把对应的行从后果中去掉。

与此绝对应,如果 c 是 null,那么,c is not false 的判断后果是 true。因而,第二个 WHERE 子句也将蕴含 c 是 null 的行。

要达到同样的成果,您能够采纳的另外一种办法是减少独自解决 null 值的子句。也就是应用语句:

WHERE c <> FALSE
   OR c IS NULL

这种模式的语句更长并且有一些冗余语句(c 被应用了两次)。长话短说,能够应用 is not false 判断来代替这个 or…is-null 的语句。更具体的内容,请参考“Binary Decisions Based on Three-Valued Results”。

SQLite 中对布尔字面量和布尔判断的反对当初和其余开源数据库靠近,惟一的差距是 SQLite 不反对 is[not] unknown(你能够应用 is [not] null 来代替)。乏味的是,这些性能在上面提到的商用产品中还不可用。

0:只反对 true,false. 不反对 notknown,如果须要,用 null 代替 1:不反对 is [not] unknown, 如果须要,用 is [not] null 代替

窗口函数

SQLite 3.25.0 引入了窗口函数。如果你晓得窗口函数,那么也晓得这是一件小事。如果你不理解窗口性能,请你本人学习如何应用。这篇文章不会具体解释窗口函数,但请置信:它是最重要的“古代”SQL 个性。

SQLite 对 over 子句的反对与其余数据库十分靠近。惟一值得注意的限度是 range 语句不反对数字或距离间隔(仅反对 current row 和 unbounded preceding|following)。在公布 sqlite 3.25.0 时,SQL Server 和 PostgreSQL 具备同样的限度。PostgreSQL 11 打消了这一限度。

0:没有变动
1:Range 范畴定义不反对 datetime 类型
2:Range 范畴不承受关键字 (只反对 unbounded 和 current row)

SQLite 对于窗口函数的反对在业界是当先的。它不反对的性能在其余一些次要产品中也同样不反对(在聚合中语句中的 distinct,width_bucket,respect|ignore nulls 和 from first|last 等语句)。

0:同样没有 ORDER BY 语句
1:不容许负偏移量,nulls 的特定解决:lead(, ‘IGNORE NULLS’),这里是字符串参数
2:没有缺省值 (第三个参数),不反对 respect|ignore nulls 语句
3:不容许负偏移量,不反对 ignore nulls 语句
4:不容许负偏移量
5:不反对 respect|ignore nulls 语句
6:不容许负偏移量,不反对 respect|ignore nulls 语句
7:nulls 的特定解决:first_value(, 1, null, ‘IGNORE NULLS’),这里是字符串参数。
8:不反对 ignore nulls 语句 9:不反对 ignore nulls 语句和 from last 语句

过滤语句

尽管 filter 语句只是语法糖——你也能够很容易地应用表达式来取得雷同的后果——我认为它也是必不可少的语法糖,因为它能使人们更加容易地学习和了解 SQL 语句。

看看上面的 select 子句,您感觉哪一个更容易了解?

SELECT SUM(revenue) total_revenue
     , SUM(CASE WHEN product = 1 
                THEN revenue
            END
          ) prod1_revenue
   ...

SELECT SUM(revenue) total_revenue
     , SUM(revenue) FILTER(WHERE product = 1) prod1_revenue
   ...

此示例很好地总结了 filter 子句的作用:它是聚合函数的后缀,能够在进行聚合之前依据特定条件,过滤掉相应的行。pivot 技术是 filter 子句最常见的用例。这包含将实体属性值(EAV)模型中的属性转换为表格的列,如果想理解更多的内容,能够参考链接“filter-Selective Aggregates”(https://modern-sql.com/featur…)。

SQLite 从版本 3.25.0 开始,在应用 over 子句的聚合函数中反对了 filter 子句,然而在应用 group by 子句的聚合函数中还不反对。可怜的是,这意味着您依然无奈在 SQLite 中应用 filter 语句来解决上述情况。你必须像以前一样应用 case 表达式。我真的心愿 SQLite 在这一点上能尽快做到。

Insert … on conflict (“Upsert”)

SQLite 从版本 3.24.0 开始,引入了“upsert”概念:它是一个 insert 语句,能够优雅地解决主键和惟一束缚的抵触。您能够抉择疏忽这些抵触(在 on conflict 语句中什么都不做)或者更新以后行(在 on conflict 语句中执行更新操作)。

这是一个特有的 SQL 扩大,即它不是规范 SQL 的一部分,因而在上面的矩阵中是灰色的。然而,SQLite 恪守与 PostgreSQL 雷同的语法来实现此性能 0。该规范提供了对 merge 语句的反对。

与 PostgreSQL 不同,SQLite 在以下语句中存在问题。

INSERT INTO target
SELECT *
  FROM source
    ON CONFLICT (id)
    DO UPDATE SET val = excluded.val

依据阐明文档,这是因为解析器无奈判断关键字 ON 是 SELECT 语句的连贯束缚还是 upsert 子句的结尾。你能够通过向查问中增加子句来解决,例如 where true。

INSERT INTO target
SELECT *
  FROM source
 WHERE true
    ON CONFLICT (id)
    DO UPDATE SET val = excluded.val

0:同样记录 insert、update、delete 和 merge 操作的错误信息 (“DML error logging”)

1:On conflict 语句不能紧挨查问的 from 语句,如果须要,能够增加  where true 语句来分隔。

重命名列

SQLite 引入的另一个特有性能是重命名基准数据库表中的列 1。规范的 SQL 不反对此类性能 2。

SQLite 遵循其余产品罕用的语法来重命名列:

ALTER TABLE … RENAME COLUMN … TO

0:请查阅 sp_rename.

其余音讯

在 2018 年,SQLite 除了在 SQL 语法上的变动,还有一些利用程序接口(API)的变动。你能够查阅 sqlite.com(https://www.sqlite.org/news.html)上的新闻局部来理解更具体的音讯。

脚标:

  • 0:SQLite 通常遵循 PostgreSQL 语法,Richard Hipp 将此称为 PostgreSQL 会怎么做(WWPD)。
  • 1:基准数据库表是指用 Create table 语句创立的数据库表。派生的数据库表(如 Select 语句返回的查问后果集)中的列名能够通过 SELECT 语句、FROM 语句或 WITH 语句来进行扭转
  • 2:据我所知,兴许能够通过可更新视图或派生的列来模仿该性能。
退出移动版