SQL優化經驗
SQL優化經驗:
1. 避免SQL中的函式呼叫,否則會產生很多的遞迴呼叫。
2. 如果使用函式呼叫,儘量在最外層使用函式呼叫,否則會產生很多次的遞迴呼叫。
3. 插入多行資料的時候,可以考慮集合寫法。
eg: insert into t SELECT LEVEL FROM dual CONNECT BY LEVEL < 10 ;
這樣的寫法比寫for迴圈會快很多。
4. 只取你所需要的列,訪問檢視會更快,因為如果你訪問的列越少,訪問的表也越少,那麼在執行計劃中,可能涉及的表越少,訪問效率越高。
5. 只取你所需要的列,索引讀無需回表了。
針對select count(*) from t的優化方案:
1. 索引什麼都不建立。(可能最慢)
2. 建立普通索引。
3. 建立點陣圖索引。
4. 建立物化檢視。
5. 快取結果集(select /*+ result_cache */ count(*) from t ;)
如果結果集改變了,這個快取中的資料會失效。而不會查錯。如果經常改變,就會多做事。這種優化就沒有用了。
下面舉個例子。
將1到1000000數字插入到T表:
速度由慢到快的優化方式 :
1. 使用儲存過程迴圈,並且使用動態sql ,並未繫結變數。
2. 使用儲存過程迴圈,並且使用動態sql ,使用繫結變數。
3. 使用儲存過程迴圈,使用靜態sql. 每次插入資料都commit .
4. 使用儲存過程迴圈,使用靜態sql. 批量提交資料。
5. 使用集合的寫法。 insert into t SELECT rownum FROM dual CONNECT BY LEVEL < 1000000 ; commit ;
6. 使用直接路徑寫法:create table t as select rownum X from dual connect by level<1000000 ;
7. 使用並行。 create table t nologging parallel 64 as select rownum x from dual connect by level < 1000000 ;
count(*)將返回表格中所有存在的行的總數包括值為null的行,然而count(列名)將返回表格中除去null以外的所有行的總數(有預設值的列也會被計入).
distinct 列名,得到的結果將是除去值為null和重複資料後的結果.
可以自己去試驗一下下面三種情況的執行結果:
select count(distinct sal) from test;
select count(sal) from test;
select count(*) from test;
not in 與 not exist的測試:
test2中object_id含有空的資料。下面看一下執行計劃:
18:15:47 SQL> select * from test t where not exists(
18:16:09 2 select 1 from test2 i where i.object_id=t.object_id
18:16:09 3 ) ;
已選擇71594行。
執行計劃
----------------------------------------------------------
Plan hash value: 2923433643
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 72537 | 7792K| 565 (1)| 00:00:07 |
|* 1 | HASH JOIN RIGHT ANTI| | 72537 | 7792K| 565 (1)| 00:00:07 |
| 2 | TABLE ACCESS FULL | TEST2 | 6323 | 82199 | 281 (0)| 00:00:04 |
| 3 | TABLE ACCESS FULL | TEST | 72537 | 6871K| 283 (1)| 00:00:04 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("I"."OBJECT_ID"="T"."OBJECT_ID")
Note
-----
- dynamic sampling used for this statement (level=2)
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
6775 consistent gets
0 physical reads
0 redo size
3443327 bytes sent via SQL*Net to client
52908 bytes received via SQL*Net from client
4774 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71594 rows processed
看not in的執行計劃:
18:16:18 SQL> select * from test t where t.object_id not in(
18:16:34 2 select i.object_id from test2 i
18:16:34 3 ) ;
未選定行
執行計劃
----------------------------------------------------------
Plan hash value: 1660021635
--------------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 72537 | 7792K| 565 (1)| 00:00:07
|
|* 1 | HASH JOIN RIGHT ANTI NA| | 72537 | 7792K| 565 (1)| 00:00:07
|
| 2 | TABLE ACCESS FULL | TEST2 | 6323 | 82199 | 281 (0)| 00:00:04
|
| 3 | TABLE ACCESS FULL | TEST | 72537 | 6871K| 283 (1)| 00:00:04
|
--------------------------------------------------------------------------------
-
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T"."OBJECT_ID"="I"."OBJECT_ID")
Note
-----
- dynamic sampling used for this statement (level=2)
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
1184 bytes sent via SQL*Net to client
405 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
原來表連線順序的說法早就過時了,那是基於規則的時代,現在我們是基於代價的。與順序無關。
下面可以看一下如下的基於規則的例子來實驗:
select /*+rule*/ count(*) from tab_big,tab_small ;
select /*+rule*/ count(*) from tab_small,tab_big ;
檢視檢視不需要的欄位儘量不要顯示出來。可以節省效率:
下面看個例子:
drop table t1 cascade constraints purge;
drop table t2 cascade constraints purge;
create table t1 as select * from dba_objects;
create table t2 as select * from dba_objects where rownum<=10000;
update t1 set object_id=rownum ;
update t2 set object_id=rownum ;
commit;
create or replace view v_t1_join_t2
as select t2.object_id,t2.object_name,t1.object_type,t1.owner from t1,t2
where t1.object_id=t2.object_id;
set autotrace traceonly
set linesize 1000
select * from v_t1_join_t2;
select object_id,object_name from v_t1_join_t2;
--做個試驗
alter table T1 add constraint pk_object_id primary key (OBJECT_ID);
alter table T2 add constraint fk_objecdt_id foreign key (OBJECT_ID) references t1 (OBJECT_ID);
select * from v_t1_join_t2;
select object_id,object_name from v_t1_join_t2;
看執行計劃,可以看出來,第二個語句只掃描了一個表的資料,而第一個語句,掃描了兩個表的資料。
大表建議使用分割槽:
drop table part_tab purge;
create table part_tab (id int,col2 int,col3 int)
partition by range (id)
(
partition p1 values less than (10000),
partition p2 values less than (20000),
partition p3 values less than (30000),
partition p4 values less than (40000),
partition p5 values less than (50000),
partition p6 values less than (60000),
partition p7 values less than (70000),
partition p8 values less than (80000),
partition p9 values less than (90000),
partition p10 values less than (100000),
partition p11 values less than (maxvalue)
)
;
insert into part_tab select rownum,rownum+1,rownum+2 from dual connect by rownum <=110000;
commit;
create index idx_par_tab_col2 on part_tab(col2) local;
create index idx_par_tab_col3 on part_tab(col3) ;
drop table norm_tab purge;
create table norm_tab (id int,col2 int,col3 int);
insert into norm_tab select rownum,rownum+1,rownum+2 from dual connect by rownum <=110000;
commit;
create index idx_nor_tab_col2 on norm_tab(col2) ;
create index idx_nor_tab_col3 on norm_tab(col3) ;
set autotrace traceonly statistics
set linesize 1000
set timing on
select * from part_tab where col2=8 ;
select * from norm_tab where col2=8 ;
select * from part_tab where col2=8 and id=2;
select * from norm_tab where col2=8 and id=2;
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29196873/viewspace-1142130/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SQL 優化經驗總結34條SQL優化
- SQL語句優化--十條經驗SQL優化
- SQL優化經驗總結34條SQL優化
- 詳解SQL效能優化十條經驗SQL優化
- SQL優化經驗總結34條(一)SQL優化
- SQL優化經驗總結34條(二)SQL優化
- 高手詳解SQL效能優化十條經驗SQL優化
- JVM 優化經驗總結JVM優化
- 分享彼此的優化經驗優化
- 提高mysql千萬級大資料SQL查詢優化30條經驗(Mysql索引優化注意)MySql大資料優化索引
- (轉)例項分析:MySQL優化經驗MySql優化
- 由一次 UPDATE 過慢 SQL 優化而總結出的經驗SQL優化
- 線上Linux伺服器優化經驗Linux伺服器優化
- MySQL效能優化的最佳21條經驗MySql優化
- Java集合類操作優化經驗總結Java優化
- MySQL MyISAM/InnoDB高併發優化經驗MySql優化
- 網站前端優化一些小經驗網站前端優化
- MySQL效能優化的21條最佳經驗MySql優化
- 模擬經營遊戲《Project Hospital》的優化經驗遊戲Project優化
- 【SQL優化】SQL優化工具SQL優化
- SQL Server優化之SQL語句優化SQLServer優化
- PHP MySQL效能優化的最佳16條經驗PHPMySql優化
- 遊戲開發效能優化經驗總結遊戲開發優化
- MySQL 效能優化的最佳 20+ 條經驗MySql優化
- 關於URL優化的一些經驗優化
- MySQL效能優化的最佳20+條經驗MySql優化
- SQL優化SQL優化
- with as優化sql優化SQL
- 效能優化案例-SQL優化優化SQL
- 高手詳解SQL效能最佳化十條經驗SQL
- 一次非常有趣的 SQL 優化經歷SQL優化
- 一次非常有趣的sql優化經歷SQL優化
- 安卓應用效能除錯和優化經驗分享安卓除錯優化
- 高併發服務的幾條優化經驗優化
- 元件庫webpack構建速度優化經驗總結元件Web優化
- MySQL資料庫效能優化的21條經驗MySql資料庫優化
- 儲存過程編寫經驗和優化措施儲存過程優化
- 資料庫優化 - SQL優化資料庫優化SQL