2016-03-30 34 views
2

我有两个疑问:自动检查两个SQL查询在语义上是相等

'UPDATE foo SET bar = baz WHERE a = b AND c = d' 

'UPDATE foo SET bar = baz WHERE c = d AND a = b' 

都是语义上相等(他们这样做),但一个简单的比较,将陈述他们不同,因为第一个有a = b AND c = d,而第二个使用c = d AND a = b

如何检查两个查询在语义上是否相等?

这是一个明显简单的例子,可以通过在WHERE节点处对语法树进行简单的字母排序来解决。我对通用的方法感兴趣,它也可以解决更复杂的查询 - 即使使用子查询。

进一步的限制是我没有访问数据库的权限,只能使用查询字符串。因此,运行查询是没有问题的,因为它不会反映查询的平等性。

为上面以粗体显示的文本的例子:

FooTable:

A | B | C 
1 | xx | xx 
2 | yy | zz 

FooTable ':(FooTable' 是FooTable不同的数据库上)

A | B | C 
1 | xx | xx 
2 | ee | zz 
3 | ss | xx 

例为什么运行查询将不会产生有效结果:

1)在同一个数据库查询:

UPDATE FooTable SET B = 'rr' WHERE C = 'xx' 

UPDATE FooTable SET B = 'rr' WHERE C = 'xx' OR B = 'ss' 

两个查询将导致完全一样的,但平凡不等于。包括不同的数据库(相同的模式,但不同的数据)时

2)查询:

SELECT A,B,C FROM FooTable where C = 'xx' 

AND

SELECT A,B,C FROM FooTable' where C = 'xx' 

这些两个查询是平凡语义相等,但不会产生相同的结果。

+0

运行它们,并比较结果集? – Stewart

+0

在两者上运行解释计划,然后运行它们并比较结果? – sagi

+0

@Stewart我无法访问运行查询的数据库。即使运行/比较和重置数据库之后的开销看起来像是一种有很多开销的方法。这因此不适用于大量的查询。 (Same @sagi) – Sim

回答

1

这个任务确实不是微不足道的。

实际上,您必须构建您自己的查询解析器和优化器。这是优化程序的任务 - 在执行计划中转换查询运算符,使查询的最终结果对基础表中的任何可能数据保持不变(考虑所有约束)。智能优化器能够针对看起来非常不同的查询生成完全相同的计划(例如IN vs EXISTS),它们简化并统一了WHERE子句中的逻辑条件,可以沿着执行树推动谓词并执行许多其他操作。

从头开始编写这样的优化器会很困难,但是您可以查看现有的开源数据库(Postgres?)并查看是否可以从那里借用某些东西。

另一种更实用的方法是利用现有数据库之一,而不是运行查询,请优化器向您返回生成的执行计划。然后,您可以比较执行计划,而不是比较原始SQL文本。如果计划是相同的,那么原始查询是100%相等的。如果计划不同,优化器仍然可能没有足够的智能来推断查询是相同的,但您必须接受错误否定的可能性。

我会看看几个不同的数据库,看看你可以从他们的优化器使用内置功能获得什么样的信息。在任何情况下,生成的执行计划都应该更加结构化,使原始SQL文本更容易自动进行比较。

+0

这听起来像一个声音选项。我会研究这一点,如果证明可行,我会接受这个答案。目前的问题在于,它比(但)实用的解决方案更抽象,因此接受它而不进行验证可能为时过早。 – Sim

+0

我选择了一个更简单但不“完美”的方法。我现在删除比较或赋值中的所有值,删除所有空格,然后按字母顺序排列语法树,最后比较字符串。这远远不是我最初想要的,但更简单,目前足以解决我的问题。但由于这是迄今为止唯一的答案,听起来很合理,我接受这个问题作为答案。 – Sim