2016-03-30 36 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