sql語句中常量的處理
sql語句中常量的處理 =========================================================== 作者: yangtingkun(http://yangtingkun.itpub.net) 發表於: 2005.03.01 00:24 分類: ORACLE 出處: http://yangtingkun.itpub.net/post/468/20038 --------------------------------------------------------------- 看到論壇中一個帖子:http://www.itpub.net/326343.html 兩個sql語句的執行計劃完全相同,但是執行花費的時間相差了近一倍。於是打算借這個問題說說如何處理常量可以使sql執行的更快。 當CBO發現表示式中存在常量或常量表示式時,最佳化器會在SQL執行之前將表示式的值計算出來,避免在表示式中進行多次計算。但是最佳化器無法將等號(不等號、大於號、小於號等)一邊的常量移動到等式的另一邊。 舉例說明: COL = 1000 COL = 500 + 500 COL – 500 = 500 雖然上面的三個等式是等價的,但是CBO只能將第二個轉化為第一個等式,而第三個最佳化器是沒有辦法最佳化的。 第三個等式由於對列包含了運算,因此不能使用這個列的索引(當然可以使用函式索引)。不考慮索引的因素,假設COL列上沒有索引,都執行全表掃描操作,第三種方式仍然是最費時的。對於全表掃描,Oracle會根據等式的條件對錶中每條記錄進行過濾,對於1、2來說,這裡只是一個比較的過程。而對於3來說,對於Oracle每條記錄都要執行一個“-500”的操作,然後在與500比較,當資料量大的時候,必然會造成一定效能問題。論壇中那個帖子中遇到的就是這個問題。 下面看一個經過簡化的例子: 首先構造一個居然一定資料量的表。 SQL> create table t as select * from dba_objects; 表已建立。 SQL> insert into t select * from t; 已建立6273行。 SQL> insert into t select * from t; 已建立12546行。 SQL> insert into t select * from t; 已建立25092行。 SQL> insert into t select * from t; 已建立50184行。 SQL> insert into t select * from t; 已建立100368行。 SQL> insert into t select * from t; 已建立200736行。 SQL> commit; 提交完成。 SQL> select count(*) from t; COUNT(*) ---------- 401472 然後尋找包含較多資料的一天用於測試。 SQL> select trunc(created), count(*) from t group by trunc(created) 2 having count(*) > 10000; TRUNC(CREATED) COUNT(*) ------------------- ---------- 2004-06-29 00:00:00 358144 2004-11-15 00:00:00 34304 下面包括4條sql語句,這4條sql語句完全是等價的。執行計劃也沒有其它的選擇,只能是全表掃描,來測試一下它們所需的執行時間。 為了避免資料快取帶來的誤差,每個sql執行兩次,取第二次執行時間。 語句一:推薦寫法 SQL> set timing on SQL> select count(*) 2 from t 3 where created >= to_date('2004-06-29 00:00:00', 'yyyy-mm-dd hh24:mi:ss') 4 and created < to_date('2004-06-30 00:00:00', 'yyyy-mm-dd hh24:mi:ss') 5 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 00.08 SQL> select count(*) 2 from t 3 where created >= to_date('2004-06-29 00:00:00', 'yyyy-mm-dd hh24:mi:ss') 4 and created < to_date('2004-06-30 00:00:00', 'yyyy-mm-dd hh24:mi:ss') 5 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 00.07 語句二:如果不能避免常量的計算或型別轉化,儘量讓計算或轉化的結果直接等於列的值,不要對列進行計算或轉化。 SQL> select count(*) 2 from t 3 where created >= to_date(to_char(to_date('2004-06-29 00:00:00', 'yyyy-mm-dd hh24:mi:ss') - 123.456, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') + 123.456 4 and created < to_date(to_char(to_date('2004-06-30 00:00:00', 'yyyy-mm-dd hh24:mi:ss') + 1000, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') - 1000 5 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 00.09 SQL> select count(*) 2 from t 3 where created >= to_date(to_char(to_date('2004-06-29 00:00:00', 'yyyy-mm-dd hh24:mi:ss') - 123.456, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') + 123.456 4 and created < to_date(to_char(to_date('2004-06-30 00:00:00', 'yyyy-mm-dd hh24:mi:ss') + 1000, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') - 1000 5 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 00.08 即使包含了比較複雜的運算和多次資料轉化,但是常量在執行開始之間就計算好了,因此,一次的計算不會對查詢帶來多大的影響。 語句三: SQL> select count(*) 2 from t 3 where to_char(created, 'yyyy-mm-dd') = '2004-06-29' 4 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 01.02 SQL> select count(*) 2 from t 3 where to_char(created, 'yyyy-mm-dd') = '2004-06-29' 4 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 01.03 由於對於每條記錄都要對CREATED列進行型別轉化,因此會耗費相當多的執行時間。 語句四: SQL> select count(*) 2 from t 3 where to_char(created, 'yyyy-mm-dd hh24:mi:ss') >= '2004-06-29 00:00:00' 4 and to_char(created, 'yyyy-mm-dd hh24:mi:ss') <= '2004-06-29 23:59:59' 5 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 02.02 SQL> select count(*) 2 from t 3 where to_char(created, 'yyyy-mm-dd hh24:mi:ss') >= '2004-06-29 00:00:00' 4 and to_char(created, 'yyyy-mm-dd hh24:mi:ss') <= '2004-06-29 23:59:59' 5 group by owner; COUNT(*) ---------- 448 99968 223872 25472 8384 已用時間: 00: 00: 02.04 由於包含了兩次條件語句,對於每條記錄需要對CREATED列進行兩次轉化,因此所需時間是語句三的二倍。 因此,在寫sql時,應該儘量避免對列操作,這樣不僅會導致無法使用索引,而且還會增加執行成本,導致sql執行速度變慢。[@more@]
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16396910/viewspace-1029576/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle sql 語句中帶有特殊的字元處理OracleSQL字元
- sql語句中as的用法SQL
- sql語句中JOIN ON 的使用SQL
- sql語句中#{}和${}的區別SQL
- sql語句中as的用法和作用SQL
- sql語句中select……as的用法SQL
- windows批處理之五-for語句中的檔名擷取Windows
- SQL語句中exists和in的區別SQL
- SQL語句中not in 和not exist的區別SQL
- sql語句中as的意思是什麼SQL
- 在sql語句中替換Not In 的方法SQL
- SQL 語句中關於 NULL 的那些坑SQLNull
- SQL語句中NULL的真實含義SQLNull
- 總結SQL語句中的優化提示SQL優化
- MyBatis在SQL語句中取list的大小MyBatisSQL
- SQL語句的處理過程SQL
- SQL Server 2008 中SQL查詢語句中欄位值不區分大小寫問題處理SQLServer
- SQL語句中SELECT語句的執行順序SQL
- MyBatis的使用三(在sql語句中傳值)MyBatisSQL
- SQL語句的處理過程修正SQL
- SQL語句中的AND和OR執行順序問題SQL
- 如何自動填充SQL語句中的公共欄位SQL
- Oracle SQL 語句中正規表示式的應用OracleSQL
- sql語句中較為重要的查詢邏輯SQL
- SQL語句中的單引號與雙引號SQL
- Python 提取出SQL語句中Where的值的方法PythonSQL
- SQL語句中聚合函式忽略NULL值的總結SQL函式Null
- oracle 對於SQL語句中物件名的解析順序OracleSQL物件
- sql語句中where一定要放在group by 之前SQL
- SQL語句中不同的連線JOIN及SQL中join的各種用法SQL
- pl/sql 異常處理的概念和術語SQL
- oracle動態sql語句處理(轉)OracleSQL
- Oracle的語句中的提示Oracle
- SQL Server SQL語句中的函式呼叫與Oracle SQL語句函式呼叫一個有趣的差別SQLServer函式Oracle
- SQL語句中的rank () over , row_number() over ,rank_dense ()SQL
- 【SQL】Oracle SQL處理的流程SQLOracle
- Oracle一個SQL語句的處理過程(轉)OracleSQL
- 使用預處理PreparedStatement執行Sql語句SQL