過濾操作可以幫助建立與靜態SQL動態查詢。特別是當列列表是靜態的時候。
您可能已經考慮過此方法,但出於性能原因將其丟棄。 「如果我們只需要從其中一個結果中獲得結果 ,爲什麼要執行每個SQL塊?」運氣好的話,優化程序已經爲您執行FILTER
操作。
實例查詢
首先創建等待每次運行時間5秒的功能。它將幫助查找哪些查詢塊被執行。
create or replace function slow_function return number is begin
dbms_lock.sleep(5);
return 1;
end;
/
該靜態查詢由綁定變量控制。有三種查詢塊,但整個查詢在5秒內運行,而不是15
declare
v_sum number;
v_query1 number := 1;
v_query2 number := 0;
v_query3 number := 0;
begin
select sum(total)
into v_sum
from
(
select total from (select slow_function() total from dual) where v_query1 = 1
union all
select total from (select slow_function() total from dual) where v_query2 = 1
union all
select total from (select slow_function() total from dual) where v_query3 = 1
);
end;
/
執行計劃
這表現並不好運氣的結果;這不僅僅是Oracle在另一個之前隨機地執行一個謂詞。 Oracle在運行時分析綁定變量,甚至不執行不相關的查詢塊。這就是以下FILTER
的操作。 (這是一個不好的名字,很多人通常把所有的謂詞稱爲「過濾器」,但是其中只有一部分會導致FILTER
的操作。)
select * from table(dbms_xplan.display_cursor(sql_id => '0cfqc6a70kzmt'));
SQL_ID 0cfqc6a70kzmt, child number 0
-------------------------------------
SELECT SUM(TOTAL) FROM (SELECT TOTAL FROM (SELECT SLOW_FUNCTION()
TOTAL FROM DUAL) WHERE :B1 = 1 UNION ALL SELECT TOTAL FROM (SELECT
SLOW_FUNCTION() TOTAL FROM DUAL) WHERE :B2 = 1 UNION ALL SELECT TOTAL
FROM (SELECT SLOW_FUNCTION() TOTAL FROM DUAL) WHERE :B3 = 1)
Plan hash value: 926033116
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 6 (100)| |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | VIEW | | 3 | 39 | 6 (0)| 00:00:01 |
| 3 | UNION-ALL | | | | | |
|* 4 | FILTER | | | | | |
| 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
|* 6 | FILTER | | | | | |
| 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
|* 8 | FILTER | | | | | |
| 9 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter(:B1=1)
6 - filter(:B2=1)
8 - filter(:B3=1)
問題
的FILTER
操作不良記錄。我無法詳細解釋它何時有效或無效,以及它究竟影響了查詢的其他部分。例如,在解釋計劃的Rows
估計是3,但在運行時,甲骨文應該能夠輕鬆地估計基數爲1。顯然,執行計劃是不是動態的,即基數估計差可能會導致以後的問題。另外,我看到了一些奇怪的情況,靜態表達式沒有被適當地過濾。但是如果查詢使用簡單的相等謂詞,它應該沒問題。
這種方法允許你刪除所有動態SQL,並用大的靜態SQL語句替換它。這有一些優點;動態SQL通常是「醜陋」的,難以調試。但只熟悉程序編程的人往往會認爲單個SQL語句是一個巨大的上帝功能,這是一種不好的做法。他們不會明白,UNION ALL
S創建SQL的獨立塊
動態SQL仍可能會更好
一般來說,我會建議對這種方法。你有什麼好,因爲它看起來好。動態SQL的主要問題是人們不把它當作真正的代碼來對待;它沒有被評論或格式化,最終看起來像一個沒有人能理解的可怕混亂。如果你能夠花費額外的時間來生成乾淨的代碼,那麼你應該堅持。
是你的問題「如何在不生成動態查詢的情況下生成動態查詢?」 – Ben
採取點!我的推理是我所有的查詢都有相同的結構:所以也許更精確的總結是'我可以創建多態遊標嗎?' – Xophmeister