分頁語句是資料庫開發和應用場景比較常見的需求,即按照特定的where條件進行過濾,然後在按照乙個或者多個條件進行排序(如果不進行排序無法確執行時候無法返回相同的結果),最後取其中的前十行或者幾十行。
一般分頁語句消耗資源的地方有兩點:
1、返回where條件過濾的結果集;
2、是對這個結果集進行排序,如果表過大同時對返回的結果集排序勢必導致效能嚴重下降,針對分頁語句效能低下的原因。
優化分頁語句的核心思想:
1、建立效率高的索引返回盡量少的結果集排序;
2、因為索引是有序的,直接讓資料庫讀取有序索引資料避免進行排序。
下面就針對不同的分頁語句場景做如何優化。 1
正確的分頁語句框架
分頁場景一
:針對分頁語句的優化
首先我們要確定正確的分頁語句框架,如果不按照正確的分頁語句框架編寫,會嚴重影響oracle選擇正確的執行計畫,正確的分頁語句框架如下:
select * from
( select * from
( select a.*,rownum rn from
( 寫好的sql語句 ) a
) where rownum<=m
) where rn>=n;
針對正確的分頁語句和錯誤的分頁語句會產生不同的執行計畫,舉例如下:
sql> create table t as select * from dba_objects;
table created.
sql> select count(*) from t;
count(*)
----------
497070
我們要寫好的sql語句,如下:
select * from t where object_id<1000 返回前10行
針對這個sql語句,如果t表比較大的話,全表掃瞄就會非常消耗資源,我們針對object_id列建立索引即可。object_id列選擇性非常高,對1000列進行排序效能也很高。建立如下索引:
create index t_idx_id on t(object_id);
然後再套用正確的分頁語句框架,去執行高階執行計畫:
set linesize 200 pagesize 200
alter session set statistics_level=all;
select * from
( select * from
( select a.*,rownum rn from
( select * from t where object_id<1000 ) a
) where rownum<=10
) where rn>=0;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
採用正確的分頁語句框架執行計畫走的是t_idx_id索引,分頁語句顯示10行,執行計畫中a-rows是10行。我們再看看採用其他錯誤分頁語句顯示的高階執行計畫:
從錯誤的執行語句框架中我們可以看到,只要不是正確分頁語句框架,oracle都會掃瞄<1000行最後顯示10行資料。
針對上述語句的優化方案我們需要注意2點:
1、採用正確的分頁語句框架;
2、針對where條件建立選擇性高、效率高、索引返回少的結果集。 2
order by 分頁
分頁場景二
: select * from t order by object_id 基於某列排序再分頁
因為索引是排序的,我們可以利用索引的排序功能。在排序的分頁語句中如果我們讓分頁語句直接按照公升序或者降序掃瞄索引,這樣的話就避免了全表掃瞄再排序的這種消耗資源操作。但是我們不確定object_id列是否有非空約束,由於索引是不存空值的,為了能夠保證可能為空的object_id列也存在索引中,我們要在索引中新增乙個組合列的常量索引,建立索引語句如下:
create index t_idx_id0 on t (object_id,0);
注:如果有些優化器沒走索引可以在sql語句中增加乙個索引的hint。 3
where等值條件過濾order by分頁
分頁場景三
: select * from t where owner=』sys』 order by object_id 有where條件過濾,然後基於某列排序再分頁
這類分頁語句我們要如何建立索引? 因為oracle對這類語句執行過程是先過濾where條件再排序,所以我們建立乙個組合索引,給予owner,object_id列組合(不能顛倒)
create index t_idx_owner_id on t (owner,object_id);
以此類推,where owner='sys' order by object_id, object_name 這類基於 owner,object_id,object_name列建組合索引。 4
where不等值條件過濾order by分頁
分頁場景四
: select * from t where where object_id<100000 order by owner 語句中的where條件是非等值,然後order by 其他列
這種情況我們就不能按照【分頁場景三】進行優化,這類語句我們要分兩種情況:
第一種where條件過濾後的結果集比較少,我們就採用【分頁場景一】進行優化直接建立效率高的索引。create index t_idx_owner_id on t (owner,object_id);第二種where條件過濾後結果集比較多,這種我們就要 order by列在前,不等值列在後建立組合索引。
注:以上兩種情況沒有明顯的分界線,特別是針對反對結果集比較適中的情況,還要綜合比較兩種建立索引方法誰的執行效率更高而採用哪種方案。 5
多表關聯的分頁語句
分頁場景五
:多表關聯的分頁如何優化select * from a,b where a.id=b.id order by a.id;
這類分頁語句的優化思想是:既然是多表關聯的分頁語句,一定是走巢狀迴圈,不能走hash連線,最後要order by 某個表,一定是 order by的那個表做驅動表,同時驅動表的 order by列必須有索引。 6
無法優化的分頁語句
無法優化的分頁場景
:但是如果是這種需求select * from a,b where a.id=b.id order by a.xx,b.*** 這種需要對兩個表排序情況下就無解了(為什麼會搞基於兩個表排序的需求,**京東的商品排序大多數是只按照一種屬性排序,如按照銷量排序,按照**排序,綜合排序),這種情況需要乾掉乙個 order by 的列。
如果分頁語句中有distinct, group by等需要把錶資料全部掃瞄之後再去排序分頁的,這種就無法用專門分頁語句進行優化了。 7
總結以上幾種分頁場景基本包含了目前主要的分頁語句的需求和實現,不同的分頁語句有一種或者幾種優化方案。首先根據【優化場景一】的內容,先選擇標準的分頁語句框架,然後判斷whete條件過濾後的結果集條數是多還是少。如果返回結果集少,則建立效率高的索引;如果返回結果集非常多,則考慮【分頁場景二,三,四】,為分頁語句建立乙個排序過濾好的索引直接返回結果。對於【無法優化的分頁場景】,就要考慮其他手段了,比如說調整分頁需求,增加where過濾條件,對大表進行分割槽和**等其他優化方案。
分頁語句優化
技巧3 分頁語句優化 分頁語句,一般都有order by column desc asc 分頁語句的優化技巧 1.分頁sql要想快最好走索引,根據order by asc desc 用hint index asc index desc 強制它走索引index full scan descending...
MySQL分頁效能優化
在對大表進行分頁時,如果在服務端實現分頁,大多數情況採用sql的limit語法來實現。但是當頁數越來越大時,效能很可能成為問題,尤其是需要查詢表的所有字段。1.索引與非索引字段 在查詢的結果集中,如果只包含索引字段,效能相比於包含非索引字段,差別很大。下面是乙個簡單的例子,在大約50w行的表上操作 ...
mysql 分頁效能優化
最簡單的分頁方法是這樣的 select from exarticletemp order by createdate desc limit 10000,10 該表中存在5w左右資料 執行時間平均在10s左右,因此該種方式在資料量大的情況下查詢效率極低。優化方式有以下幾種 1.此種方式平均在7 8s之...