SQL语句的确定性

Posted cdai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL语句的确定性相关的知识,希望对你有一定的参考价值。

SQL语句的确定性

1.确定性的用途

SQL语句的确定性,从字面上理解就是执行一条语句始终有同样的结果。根据语句类型的不同(DQL/DML/DDL),这里的结果指的可能是查询结果,也可能是副作用,比如对数据库状态的修改。在思考确定性的准确定义之前,我们先看下面三个判断SQL语句确定性的用途:

  • 数据复制(Replication):分布式数据库要保持主副本和从副本之间的数据一致性,两种常见的策略是基于语句和基于行数据。前者只发送要执行的语句,比如DML的INSERT/UPDATE,这就要保证这条语句具有确定性,即在不同服务器上重复执行都能得到相同的结果。
  • 对比测试:测试数据库一个简单的策略是用另一个数据库跑同样的查询,在测试数据相同的情况下,看结果是否相同。比如你要开发一个数据库,测试时可以用mysql,或者小巧的嵌入式数据库比如H2/SQLite/Derby作为对比。当发现不一致时,就要考虑是否是自己的数据库实现有问题,还是查询本身的不确定性导致了结果不同。
  • 结果集缓存:出于性能考虑,对于重复执行的查询,其结果可以保存到缓存服务器中留作后用。比如计算很重的JOIN或者聚合,可以将其结果保存到缓存服务器的内存或磁盘上,类似算法优化策略中的预计算预处理。这种缓存只适用于确定性的查询,否则用户会得到错误的结果。

2.确定性的定义

2.1 严格定义

类似于数学上的函数,对于同样的输入,一个函数必须始终给出相同的答案。严格定义的话,SQL确定性指的是:对于同样的输入,一条语句必须始终产生相同的结果。这里的输入狭义上讲就是数据库里的数据,广义来说的话就是数据库在执行这条语句那一刻的整个状态,包括了数据、元数据、配置、Session变量等等。

2.2 反例

因为确定性语句的集合更大,所以我们可以从反例出发,看一下常见的不确定语句都包含哪些子语句:

  • 语句
    • 有LIMIT却没有ORDER BY
    • 类似地,使用了行号、排名等窗口函数却没有ORDER BY
  • SQL函数
    • ID:UUID()
    • 日期:NOW()、CURRENT_TIME()等
    • 概率:RANDOM()、SHUFFLE()等
    • 采样:各个数据库有所不同
    • 近似:APPROX_DISTINCT、PERCENTILE()等
    • 窗口函数:ROW_NUMBER()、RANK()、DENSE_RANK()等
    • 浮点数的聚合:计算顺序不同可能导致浮点数精度差异
  • 自定义函数
    • UDF:用户自定的外部函数,除非定义时声明确定性,否则当作不确定性

2.3 放宽限制

可以看出,按严格定义的话,很多SQL语句都是不确定性的。这时我们就要具体情况具体分析,根据情况可以放宽限制。比如当前的使用场景是缓存的话,像浮点数聚合也许是可以接受的,于是当作确定性语句去缓存其结果。


3.如何判断确定性

3.1 基于语法

最简单的检查方法就是基于语法树,发现了“黑名单”中的函数出现在了语法树上,就认为当前语句是不确定性的。这种实现方式基本上是静态的,基于语法树上的结点信息(比如函数名字)和一个硬编码的黑名单做出判断。优点是非常简单直接,缺点就是不够灵活、不易扩展和维护。

3.2 基于语义

基于语义的实现方式发生在语义分析之后,这时我们已经得到了一条SQL语句的所有语义信息。举个例子,比如最重要的信息就是语句中所有符号(Symbol)的类型是什么。相比语法树,我们得到了更多的信息:

  1. 语义信息中已经包含了每个表达式的信息,如果没有确定性信息的,这是加入的合适位置
  2. 有了语义信息,更细粒度的检查变成可能,比如所有函数参数的信息等,虽然可能不需要这样做
  3. 此时我们还可以得到所有支持函数的全集,这样就能判断出哪些是外部函数

参考

  1. IBM:https://www.ibm.com/docs/en/psfa/1.6?topic=environment-non-deterministic-sql
  2. SQLite:https://www.sqlite.org/deterministic.html
  3. SQLServer:https://docs.microsoft.com/en-us/sql/relational-databases/user-defined-functions/deterministic-and-nondeterministic-functions?view=sql-server-ver15

以上是关于SQL语句的确定性的主要内容,如果未能解决你的问题,请参考以下文章

SQL语句的确定性

SQL语句的确定性

SQL语句的确定性

SQL Server 2008 update语句只能更新1行数据?

sql聚合函数的应用

sql语句问题,搜索前5000条数据再过滤