缺乏对讹传的辨知力
count哪種寫法更快
--做個試驗,看看到底誰更快? drop table t purge; create table t as select * from dba_objects; --alter table T modify object_id null; update t set object_id =rownum ; set timing on set linesize 1000 set autotrace on select count(*) from t; / select count(object_id) from t; /--看來count(列)比count(*) 更快是謠傳,明明是一樣快嘛,真相是這樣嗎? ---NO!NO!NO!請繼續往下看--來來,建個索引看看 create index idx_object_id on t(object_id); select count(*) from t; /select count(object_id) from t; /--哇,原來真的是用COUNT(列)比COUNT(*)要快啊,因為COUNT(*)不能用到索引,而COUNT(列)可以,真相真是如此嗎?--NONONO!還請看官繼續往下看alter table T modify object_id not null;select count(*) from t; / select count(object_id) from t; /--看來count(列)和count(*)其實一樣快,如果索引列是非空的,count(*)可用到索引,此時一樣快!真相真是如此嗎?---NONONO!其實兩者根本沒有可比性,性能比較首先要考慮寫法等價,這兩個語句根本就不等價!!!count各列性能統計
COUNT對話正確與否結論
終于明白count誰快
----看官們,看完這個試驗,你就明白了最佳字段順序(結論:越往后的列訪問CPU開銷大)驗證腳本1 (先構造出表和數據) SET SERVEROUTPUT ON SET ECHO ON ---構造出有25個字段的表T DROP TABLE t; DECLAREl_sql VARCHAR2(32767); BEGINl_sql := 'CREATE TABLE t (';FOR i IN 1..25 LOOPl_sql := l_sql || 'n' || i || ' NUMBER,';END LOOP;l_sql := l_sql || 'pad VARCHAR2(1000)) PCTFREE 10';EXECUTE IMMEDIATE l_sql; END; / ----將記錄還有這個表T中填充 DECLAREl_sql VARCHAR2(32767); BEGINl_sql := 'INSERT INTO t SELECT ';FOR i IN 1..25LOOPl_sql := l_sql || '0,';END LOOP;l_sql := l_sql || 'NULL FROM dual CONNECT BY level <= 10000';EXECUTE IMMEDIATE l_sql;COMMIT; END; /--驗證腳本2(一次訪問該表各字段驗證) execute dbms_stats.gather_table_stats(ownname=>user, tabname=>'t') SELECT num_rows, blocks FROM user_tables WHERE table_name = 'T'; --以下動作觀察執行速度,比較發現COUNT(*)最快,COUNT(最大列)最慢 DECLAREl_dummy PLS_INTEGER;l_start PLS_INTEGER;l_stop PLS_INTEGER;l_sql VARCHAR2(100); BEGINl_start := dbms_utility.get_time;FOR j IN 1..1000LOOPEXECUTE IMMEDIATE 'SELECT count(*) FROM t' INTO l_dummy;END LOOP;l_stop := dbms_utility.get_time;dbms_output.put_line((l_stop-l_start)/100);FOR i IN 1..25LOOPl_sql := 'SELECT count(n' || i || ') FROM t';l_start := dbms_utility.get_time;FOR j IN 1..1000LOOPEXECUTE IMMEDIATE l_sql INTO l_dummy;END LOOP;l_stop := dbms_utility.get_time;dbms_output.put_line((l_stop-l_start)/100);END LOOP; END; /--結論: --原來優化器是這么搞的:列的偏移量決定性能,列越靠后,訪問的開銷越大。由于count(*)的算法與列偏移量無關,所以count(*)最快。 --后面還有看圖說話,看看結果輸出的趨勢圖,就更了然了。缺乏對訛傳的辨知力(SQL編寫順序訛傳)
表的連接順序
--來來來,做一個試驗,看看SQL寫法中,表的連接順序是否很重要 drop table tab_big; drop table tab_small; create table tab_big as select * from dba_objects where rownum<=30000; create table tab_small as select * from dba_objects where rownum<=10; set autotrace traceonly set linesize 1000 set timing on select count(*) from tab_big,tab_small ; select count(*) from tab_small,tab_big ;---奇怪,以上實驗發現性能是一樣的,咋回事呢,看來真是謠言啊,這真是惡意傳謠嗎?---NONONO,其實任何謠言,都是有一定的影子的。大家看看俺下面的語句,比較一下性能。 select /*+rule*/ count(*) from tab_big,tab_small ; select /*+rule*/ count(*) from tab_small,tab_big ;--看明白了,顯然上一條性能好于下一條,謠言也不是真的無中生有!結論:原來表連接順序的說法早就過時了,那是基于規則的時代,現在我們是基于代價的。關于SQL書寫順序的試驗結論
缺乏對訛傳的辨知力(in與exists之爭)
in與exists之爭(10g)
10g執行一下 select * from v$version;drop table emp purge; drop table dept purge; create table emp as select * from scott.emp; create table dept as select * from scott.dept; set timing on set linesize 1000 set autotrace traceonly select * from dept where deptno NOT IN ( select deptno from emp ) ; select * from dept where not exists ( select deptno from emp where emp.deptno=dept.deptno) ;select * from dept where deptno NOT IN ( select deptno from emp where deptno is not null) and deptno is not null;--結論:10g與空值有關,如果確保非空,可以用到anti的半連接算法關于IN與EXIST的試驗證明(10g)
in與exists之爭(11g)
11g執行一下 select * from v$version;drop table emp purge; drop table dept purge; create table emp as select * from scott.emp; create table dept as select * from scott.dept; set timing on set linesize 1000set autotrace traceonly explain select * from dept where deptno NOT IN ( select deptno from emp ) ; select * from dept where not exists ( select deptno from emp where emp.deptno=dept.deptno) ;select * from dept where deptno NOT IN ( select deptno from emp where deptno is not null) and deptno is not null;--結論:11g與空值有關,都可以用到anti的半連接算法,執行計劃一樣,性能一樣關于IN與EXIST的試驗證明(11g)
關于IN與EXIST的試驗結論
?
最精彩的名人名言
?
?
?
?
?
?
?
?
?
?
總結
- 上一篇: HDFS的文件副本机制
- 下一篇: 不具备少做事的意识