日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

oracle in 索引_Oracle 性能优化总结

發(fā)布時間:2025/3/15 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 oracle in 索引_Oracle 性能优化总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者 |?帥性而為1號

出處 :

https://blog.csdn.net/zhushuai1221/article/details/51740846

網(wǎng)上關(guān)于SQL優(yōu)化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補(bǔ)充。

這篇文章我花費了大量的時間查找資料、修改、排版,希望大家閱讀之后,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補(bǔ)充。

一、百萬級數(shù)據(jù)庫優(yōu)化方案

1.對查詢進(jìn)行優(yōu)化,要盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。

2.應(yīng)盡量避免在 where 子句中對字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:

select id from t where num is null

最好不要給數(shù)據(jù)庫留NULL,盡可能的使用?NOT NULL填充數(shù)據(jù)庫.

備注、描述、評論之類的可以設(shè)置為 NULL,其他的,最好不要使用NULL。

不要以為 NULL 不需要空間,比如:char(100)?型,在字段建立時,空間就固定了,?不管是否插入值(NULL也包含在內(nèi)),都是占用 100個字符的空間的,如果是varchar這樣的變長字段, null 不占用空間。

可以在num上設(shè)置默認(rèn)值0,確保表中num列沒有null值,然后這樣查詢:

select id from t where num = 0

3.應(yīng)盡量避免在 where 子句中使用 != 或 <> 操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描。

4.應(yīng)盡量避免在 where 子句中使用 or 來連接條件,如果一個字段有索引,一個字段沒有索引,將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:

select id from t where num=10 or Name = 'admin'可以這樣查詢:select id from t where num = 10union allselect id from t where Name = 'admin'5.in 和 not in 也要慎用,否則會導(dǎo)致全表掃描,如:select id from t where num in(1,2,3)

對于連續(xù)的數(shù)值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

很多時候用 exists 代替 in 是一個好的選擇:

select num from a where num in(select num from b)

用下面的語句替換:

select num from a where exists(select 1 from b where num=a.num)

6.下面的查詢也將導(dǎo)致全表掃描:

select id from t where name like ‘%abc%’

若要提高效率,可以考慮全文檢索。

7.如果在 where 子句中使用參數(shù),也會導(dǎo)致全表掃描。因為SQL只有在運(yùn)行時才會解析局部變量,但優(yōu)化程序不能將訪問計劃的選擇推遲到運(yùn)行時;它必須在編譯時進(jìn)行選擇。然 而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。應(yīng)盡量避免在 where 子句中對字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:

select id from t where num/2 = 100應(yīng)改為:select id from t where num = 100*2

9.應(yīng)盡量避免在where子句中對字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。

10.不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無法正確使用索引。

11.在使用索引字段作為條件時,如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統(tǒng)使用該索引,否則該索引將不會被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如需要生成一個空表結(jié)構(gòu):

select col1,col2 into #t from t where 1=0

這類代碼不會返回任何結(jié)果集,但是會消耗系統(tǒng)資源的

13.Update 語句,如果只更改1、2個字段,不要Update全部字段,否則頻繁調(diào)用會引起明顯的性能消耗,同時帶來大量日志。

14.對于多張大數(shù)據(jù)量(這里幾百條就算大了)的表JOIN,要先分頁再JOIN,否則邏輯讀會很高,性能很差。

15.select count(*) from table;這樣不帶任何條件的count會引起全表掃描,并且沒有任何業(yè)務(wù)意義,是一定要杜絕的。

16.索引并不是越多越好,索引固然可以提高相應(yīng)的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數(shù)最好不要超過6個,若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有 必要。

17.應(yīng)盡可能的避免更新 clustered 索引數(shù)據(jù)列,因為 clustered 索引數(shù)據(jù)列的順序就是表記錄的物理存儲順序,一旦該列值改變將導(dǎo)致整個表記錄的順序的調(diào)整,會耗費相當(dāng)大的資源。若應(yīng)用系統(tǒng)需要頻繁更新 clustered 索引數(shù)據(jù)列,那么需要考慮是否應(yīng)將該索引建為 clustered 索引。

18.盡量使用數(shù)字型字段,若只含數(shù)值信息的字段盡量不要設(shè)計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連 接時會逐個比較字符串中每一個字符,而對于數(shù)字型而言只需要比較一次就夠了。

19.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節(jié)省存儲空間,其次對于查詢來說,在一個相對較小的字段內(nèi)搜索效率顯然要高些。

20.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

21.盡量使用表變量來代替臨時表。如果表變量包含大量數(shù)據(jù),請注意索引非常有限(只有主鍵索引)。

22. 避免頻繁創(chuàng)建和刪除臨時表,以減少系統(tǒng)表資源的消耗。臨時表并不是不可使用,適當(dāng)?shù)厥褂盟鼈兛梢允鼓承├谈行?#xff0c;例如,當(dāng)需要重復(fù)引用大型表或常用表中的某個數(shù)據(jù)集時。但是,對于一次性事件, 最好使用導(dǎo)出表。

23.在新建臨時表時,如果一次性插入數(shù)據(jù)量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先create table,然后insert。

24.如果使用到了臨時表,在存儲過程的最后務(wù)必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統(tǒng)表的較長時間鎖定。

25.盡量避免使用游標(biāo),因為游標(biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過1萬行,那么就應(yīng)該考慮改寫。

26.使用基于游標(biāo)的方法或臨時表方法之前,應(yīng)先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。

27.與臨時表一樣,游標(biāo)并不是不可使用。對小型數(shù)據(jù)集使用 FAST_FORWARD 游標(biāo)通常要優(yōu)于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數(shù)據(jù)時。在結(jié)果集中包括“合計”的例程通常要比使用游標(biāo)執(zhí)行的速度快。如果開發(fā)時 間允許,基于游標(biāo)的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。

28.在所有的存儲過程和觸發(fā)器的開始處設(shè)置 SET NOCOUNT ON ,在結(jié)束時設(shè)置 SET NOCOUNT OFF 。無需在執(zhí)行存儲過程和觸發(fā)器的每個語句后向客戶端發(fā)送 DONE_IN_PROC 消息。

29.盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。

30.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過大,應(yīng)該考慮相應(yīng)需求是否合理。

二、數(shù)據(jù)庫訪問性能優(yōu)化

特別說明:

1、??本文只是面對數(shù)據(jù)庫應(yīng)用開發(fā)的程序員,不適合專業(yè)DBA,DBA在數(shù)據(jù)庫性能優(yōu)化方面需要了解更多的知識;

2、??本文許多示例及概念是基于Oracle數(shù)據(jù)庫描述,對于其它關(guān)系型數(shù)據(jù)庫也可以參考,但許多觀點不適合于KV數(shù)據(jù)庫或內(nèi)存數(shù)據(jù)庫或者是基于SSD技術(shù)的數(shù)據(jù)庫;

3、??本文未深入數(shù)據(jù)庫優(yōu)化中最核心的執(zhí)行計劃分析技術(shù)。

讀者對像:

開發(fā)人員:如果你是做數(shù)據(jù)庫開發(fā),那本文的內(nèi)容非常適合,因為本文是從程序員的角度來談數(shù)據(jù)庫性能優(yōu)化。

架構(gòu)師:如果你已經(jīng)是數(shù)據(jù)庫應(yīng)用的架構(gòu)師,那本文的知識你應(yīng)該清楚90%,否則你可能是一個喜歡折騰的架構(gòu)師。

DBA(數(shù)據(jù)庫管理員):大型數(shù)據(jù)庫優(yōu)化的知識非常復(fù)雜,本文只是從程序員的角度來談性能優(yōu)化,DBA除了需要了解這些知識外,還需要深入數(shù)據(jù)庫的內(nèi)部體系架構(gòu)來解決問題。

? ? ?在網(wǎng)上有很多文章介紹數(shù)據(jù)庫優(yōu)化知識,但是大部份文章只是對某個一個方面進(jìn)行說明,而對于我們程序員來說這種介紹并不能很好的掌握優(yōu)化知識,因為很多介紹只是對一些特定的場景優(yōu)化的,所以反而有時會產(chǎn)生誤導(dǎo)或讓程序員感覺不明白其中的奧妙而對數(shù)據(jù)庫優(yōu)化感覺很神秘。

? ? ?很多程序員總是問如何學(xué)習(xí)數(shù)據(jù)庫優(yōu)化,有沒有好的教材之類的問題。在書店也看到了許多數(shù)據(jù)庫優(yōu)化的專業(yè)書籍,但是感覺更多是面向DBA或者是PL/SQL開發(fā)方面的知識,個人感覺不太適合普通程序員。而要想做到數(shù)據(jù)庫優(yōu)化的高手,不是花幾周,幾個月就能達(dá)到的,這并不是因為數(shù)據(jù)庫優(yōu)化有多高深,而是因為要做好優(yōu)化一方面需要有非常好的技術(shù)功底,對操作系統(tǒng)、存儲硬件網(wǎng)絡(luò)、數(shù)據(jù)庫原理等方面有比較扎實的基礎(chǔ)知識,另一方面是需要花大量時間對特定的數(shù)據(jù)庫進(jìn)行實踐測試與總結(jié)。

? ? ?作為一個程序員,我們也許不清楚線上正式的服務(wù)器硬件配置,我們不可能像DBA那樣專業(yè)的對數(shù)據(jù)庫進(jìn)行各種實踐測試與總結(jié),但我們都應(yīng)該非常了解我們SQL的業(yè)務(wù)邏輯,我們清楚SQL中訪問表及字段的數(shù)據(jù)情況,我們其實只關(guān)心我們的SQL是否能盡快返回結(jié)果。那程序員如何利用已知的知識進(jìn)行數(shù)據(jù)庫優(yōu)化?如何能快速定位SQL性能問題并找到正確的優(yōu)化方向?

面對這些問題,筆者總結(jié)了一些面向程序員的基本優(yōu)化法則,本文將結(jié)合實例來坦述數(shù)據(jù)庫開發(fā)的優(yōu)化知識。

? ? ?要正確的優(yōu)化SQL,我們需要快速定位能性的瓶頸點,也就是說快速找到我們SQL主要的開銷在哪里?而大多數(shù)情況性能最慢的設(shè)備會是瓶頸點,如下載時網(wǎng)絡(luò)速度可能會是瓶頸點,本地復(fù)制文件時硬盤可能會是瓶頸點,為什么這些一般的工作我們能快速確認(rèn)瓶頸點呢,因為我們對這些慢速設(shè)備的性能數(shù)據(jù)有一些基本的認(rèn)識,如網(wǎng)絡(luò)帶寬是2Mbps,硬盤是每分鐘7200轉(zhuǎn)等等。因此,為了快速找到SQL的性能瓶頸點,我們也需要了解我們計算機(jī)系統(tǒng)的硬件基本性能指標(biāo),下圖展示的當(dāng)前主流計算機(jī)性能指標(biāo)數(shù)據(jù)。

從圖上可以看到基本上每種設(shè)備都有兩個指標(biāo):

延時(響應(yīng)時間):表示硬件的突發(fā)處理能力;

帶寬(吞吐量):代表硬件持續(xù)處理能力。

從上圖可以看出,計算機(jī)系統(tǒng)硬件性能從高到代依次為:

CPU——Cache(L1-L2-L3)——內(nèi)存——SSD硬盤——網(wǎng)絡(luò)——硬盤

由于SSD硬盤還處于快速發(fā)展階段,所以本文的內(nèi)容不涉及SSD相關(guān)應(yīng)用系統(tǒng)。

根據(jù)數(shù)據(jù)庫知識,我們可以列出每種硬件主要的工作內(nèi)容:

CPU及內(nèi)存:緩存數(shù)據(jù)訪問、比較、排序、事務(wù)檢測、SQL解析、函數(shù)或邏輯運(yùn)算;

網(wǎng)絡(luò):結(jié)果數(shù)據(jù)傳輸、SQL請求、遠(yuǎn)程數(shù)據(jù)庫訪問(dblink);

硬盤:數(shù)據(jù)訪問、數(shù)據(jù)寫入、日志記錄、大數(shù)據(jù)量排序、大表連接。

根據(jù)當(dāng)前計算機(jī)硬件的基本性能指標(biāo)及其在數(shù)據(jù)庫中主要操作內(nèi)容,可以整理出如下圖所示的性能基本優(yōu)化法則:

這個優(yōu)化法則歸納為5個層次:

1、??減少數(shù)據(jù)訪問(減少磁盤訪問)

2、??返回更少數(shù)據(jù)(減少網(wǎng)絡(luò)傳輸或磁盤訪問)

3、??減少交互次數(shù)(減少網(wǎng)絡(luò)傳輸)

4、??減少服務(wù)器CPU開銷(減少CPU及內(nèi)存開銷)

5、??利用更多資源(增加資源)

由于每一層優(yōu)化法則都是解決其對應(yīng)硬件的性能問題,所以帶來的性能提升比例也不一樣。傳統(tǒng)數(shù)據(jù)庫系統(tǒng)設(shè)計是也是盡可能對低速設(shè)備提供優(yōu)化方法,因此針對低速設(shè)備問題的可優(yōu)化手段也更多,優(yōu)化成本也更低。我們?nèi)魏我粋€SQL的性能優(yōu)化都應(yīng)該按這個規(guī)則由上到下來診斷問題并提出解決方案,而不應(yīng)該首先想到的是增加資源解決問題。

以下是每個優(yōu)化法則層級對應(yīng)優(yōu)化效果及成本經(jīng)驗參考:

優(yōu)化法則

性能提升效果

優(yōu)化成本

減少數(shù)據(jù)訪問

1~1000

返回更少數(shù)據(jù)

1~100

減少交互次數(shù)

1~20

減少服務(wù)器CPU開銷

1~5

利用更多資源

@~10

接下來,我們針對5種優(yōu)化法則列舉常用的優(yōu)化手段并結(jié)合實例分析。

數(shù)據(jù)塊是數(shù)據(jù)庫中數(shù)據(jù)在磁盤中存儲的最小單位,也是一次IO訪問的最小單位,一個數(shù)據(jù)塊通??梢源鎯Χ鄺l記錄,數(shù)據(jù)塊大小是DBA在創(chuàng)建數(shù)據(jù)庫或表空間時指定,可指定為2K、4K、8K、16K或32K字節(jié)。下圖是一個Oracle數(shù)據(jù)庫典型的物理結(jié)構(gòu),一個數(shù)據(jù)庫可以包括多個數(shù)據(jù)文件,一個數(shù)據(jù)文件內(nèi)又包含多個數(shù)據(jù)塊;

ROWID是每條記錄在數(shù)據(jù)庫中的唯一標(biāo)識,通過ROWID可以直接定位記錄到對應(yīng)的文件號及數(shù)據(jù)塊位置。ROWID內(nèi)容包括文件號、對像號、數(shù)據(jù)塊號、記錄槽號,如下圖所示:

三、數(shù)據(jù)庫訪問優(yōu)化法則詳解

減少數(shù)據(jù)訪問

創(chuàng)建并使用正確的索引

數(shù)據(jù)庫索引的原理非常簡單,但在復(fù)雜的表中真正能正確使用索引的人很少,即使是專業(yè)的DBA也不一定能完全做到最優(yōu)。

索引會大大增加表記錄的DML(INSERT,UPDATE,DELETE)開銷,正確的索引可以讓性能提升100,1000倍以上,不合理的索引也可能會讓性能下降100倍,因此在一個表中創(chuàng)建什么樣的索引需要平衡各種業(yè)務(wù)需求。

索引常見問題:

索引有哪些種類?

常見的索引有B-TREE索引、位圖索引、全文索引,位圖索引一般用于數(shù)據(jù)倉庫應(yīng)用,全文索引由于使用較少,這里不深入介紹。B-TREE索引包括很多擴(kuò)展類型,如組合索引、反向索引、函數(shù)索引等等,以下是B-TREE索引的簡單介紹:

B-TREE索引也稱為平衡樹索引(Balance Tree),它是一種按字段排好序的樹形目錄結(jié)構(gòu),主要用于提升查詢性能和唯一約束支持。B-TREE索引的內(nèi)容包括根節(jié)點、分支節(jié)點、葉子節(jié)點。

葉子節(jié)點內(nèi)容:索引字段內(nèi)容+表記錄ROWID

根節(jié)點,分支節(jié)點內(nèi)容:當(dāng)一個數(shù)據(jù)塊中不能放下所有索引字段數(shù)據(jù)時,就會形成樹形的根節(jié)點或分支節(jié)點,根節(jié)點與分支節(jié)點保存了索引樹的順序及各層級間的引用關(guān)系。

?????????一個普通的BTREE索引結(jié)構(gòu)示意圖如下所示:

如果我們把一個表的內(nèi)容認(rèn)為是一本字典,那索引就相當(dāng)于字典的目錄,如下圖所示:

圖中是一個字典按部首+筆劃數(shù)的目錄,相當(dāng)于給字典建了一個按部首+筆劃的組合索引。

一個表中可以建多個索引,就如一本字典可以建多個目錄一樣(按拼音、筆劃、部首等等)。

一個索引也可以由多個字段組成,稱為組合索引,如上圖就是一個按部首+筆劃的組合目錄。

SQL什么條件會使用索引?

當(dāng)字段上建有索引時,通常以下情況會使用索引:

INDEX_COLUMN = ?

INDEX_COLUMN > ?

INDEX_COLUMN >= ?

INDEX_COLUMN < ?

INDEX_COLUMN <= ?

INDEX_COLUMN between ? and ?

INDEX_COLUMN in (?,?,...,?)

INDEX_COLUMN like ?||'%'(后導(dǎo)模糊查詢)

T1. INDEX_COLUMN=T2. COLUMN1(兩個表通過索引字段關(guān)聯(lián))

SQL什么條件不會使用索引?

查詢條件

不能使用索引原因

INDEX_COLUMN <> ?

INDEX_COLUMN not in (?,?,...,?)

不等于操作不能使用索引

function(INDEX_COLUMN) = ?

INDEX_COLUMN + 1 = ?

INDEX_COLUMN || 'a' = ?

經(jīng)過普通運(yùn)算或函數(shù)運(yùn)算后的索引字段不能使用索引

INDEX_COLUMN like '%'||?

INDEX_COLUMN like '%'||?||'%'

含前導(dǎo)模糊查詢的Like語法不能使用索引

INDEX_COLUMN is null

B-TREE索引里不保存字段為NULL值記錄,因此IS NULL不能使用索引

NUMBER_INDEX_COLUMN='12345'

CHAR_INDEX_COLUMN=12345

Oracle在做數(shù)值比較時需要將兩邊的數(shù)據(jù)轉(zhuǎn)換成同一種數(shù)據(jù)類型,如果兩邊數(shù)據(jù)類型不同時會對字段值隱式轉(zhuǎn)換,相當(dāng)于加了一層函數(shù)處理,所以不能使用索引。

a.INDEX_COLUMN=a.COLUMN_1

給索引查詢的值應(yīng)是已知數(shù)據(jù),不能是未知字段值。

注:

經(jīng)過函數(shù)運(yùn)算字段的字段要使用可以使用函數(shù)索引,這種需求建議與DBA溝通。

有時候我們會使用多個字段的組合索引,如果查詢條件中第一個字段不能使用索引,那整個查詢也不能使用索引

如:我們company表建了一個id+name的組合索引,以下SQL是不能使用索引的

Select * from company where name=?

Oracle9i后引入了一種index skip scan的索引方式來解決類似的問題,但是通過index skip scan提高性能的條件比較特殊,使用不好反而性能會更差。

我們一般在什么字段上建索引?

這是一個非常復(fù)雜的話題,需要對業(yè)務(wù)及數(shù)據(jù)充分分析后再能得出結(jié)果。主鍵及外鍵通常都要有索引,其它需要建索引的字段應(yīng)滿足以下條件:

1、字段出現(xiàn)在查詢條件中,并且查詢條件可以使用索引;

2、語句執(zhí)行頻率高,一天會有幾千次以上;

3、通過字段條件可篩選的記錄集很小,那數(shù)據(jù)篩選比例是多少才適合?

這個沒有固定值,需要根據(jù)表數(shù)據(jù)量來評估,以下是經(jīng)驗公式,可用于快速評估:

小表(記錄數(shù)小于10000行的表):篩選比例<10%;

大表:(篩選返回記錄數(shù))

??????單條記錄長度≈字段平均內(nèi)容長度之和+字段數(shù)*2

以下是一些字段是否需要建B-TREE索引的經(jīng)驗分類:

字段類型

常見字段名

需要建索引的字段

主鍵

ID,PK

外鍵

PRODUCT_ID,COMPANY_ID,MEMBER_ID,ORDER_ID,TRADE_ID,PAY_ID

有對像或身份標(biāo)識意義字段

HASH_CODE,USERNAME,IDCARD_NO,EMAIL,TEL_NO,IM_NO

索引慎用字段,需要進(jìn)行數(shù)據(jù)分布及使用場景詳細(xì)評估

日期

GMT_CREATE,GMT_MODIFIED

年月

YEAR,MONTH

狀態(tài)標(biāo)志

PRODUCT_STATUS,ORDER_STATUS,IS_DELETE,VIP_FLAG

類型

ORDER_TYPE,IMAGE_TYPE,GENDER,CURRENCY_TYPE

區(qū)域

COUNTRY,PROVINCE,CITY

操作人員

CREATOR,AUDITOR

數(shù)值

LEVEL,AMOUNT,SCORE

長字符

ADDRESS,COMPANY_NAME,SUMMARY,SUBJECT

不適合建索引的字段

描述備注

DESCRIPTION,REMARK,MEMO,DETAIL

大字段

FILE_CONTENT,EMAIL_CONTENT

如何知道SQL是否使用了正確的索引?

簡單SQL可以根據(jù)索引使用語法規(guī)則判斷,復(fù)雜的SQL不好辦,判斷SQL的響應(yīng)時間是一種策略,但是這會受到數(shù)據(jù)量、主機(jī)負(fù)載及緩存等因素的影響,有時數(shù)據(jù)全在緩存里,可能全表訪問的時間比索引訪問時間還少。要準(zhǔn)確知道索引是否正確使用,需要到數(shù)據(jù)庫中查看SQL真實的執(zhí)行計劃,這個話題比較復(fù)雜,詳見SQL執(zhí)行計劃專題介紹。

索引對DML(INSERT,UPDATE,DELETE)附加的開銷有多少?

這個沒有固定的比例,與每個表記錄的大小及索引字段大小密切相關(guān),以下是一個普通表測試數(shù)據(jù),僅供參考:

索引對于Insert性能降低56%

索引對于Update性能降低47%

索引對于Delete性能降低29%

因此對于寫IO壓力比較大的系統(tǒng),表的索引需要仔細(xì)評估必要性,另外索引也會占用一定的存儲空間。

1.2、只通過索引訪問數(shù)據(jù)

有些時候,我們只是訪問表中的幾個字段,并且字段內(nèi)容較少,我們可以為這幾個字段單獨建立一個組合索引,這樣就可以直接只通過訪問索引就能得到數(shù)據(jù),一般索引占用的磁盤空間比表小很多,所以這種方式可以大大減少磁盤IO開銷。

如:

select id,name from company where type='2';

如果這個SQL經(jīng)常使用,我們可以在type,id,name上創(chuàng)建組合索引

create index my_comb_index on company(type,id,name);

有了這個組合索引后,SQL就可以直接通過my_comb_index索引返回數(shù)據(jù),不需要訪問company表。

還是拿字典舉例:有一個需求,需要查詢一本漢語字典中所有漢字的個數(shù),如果我們的字典沒有目錄索引,那我們只能從字典內(nèi)容里一個一個字計數(shù),最后返回結(jié)果。如果我們有一個拼音目錄,那就可以只訪問拼音目錄的漢字進(jìn)行計數(shù)。如果一本字典有1000頁,拼音目錄有20頁,那我們的數(shù)據(jù)訪問成本相當(dāng)于全表訪問的50分之一。

切記,性能優(yōu)化是無止境的,當(dāng)性能可以滿足需求時即可,不要過度優(yōu)化。在實際數(shù)據(jù)庫中我們不可能把每個SQL請求的字段都建在索引里,所以這種只通過索引訪問數(shù)據(jù)的方法一般只用于核心應(yīng)用,也就是那種對核心表訪問量最高且查詢字段數(shù)據(jù)量很少的查詢。

1.3、優(yōu)化SQL執(zhí)行計劃

SQL執(zhí)行計劃是關(guān)系型數(shù)據(jù)庫最核心的技術(shù)之一,它表示SQL執(zhí)行時的數(shù)據(jù)訪問算法。由于業(yè)務(wù)需求越來越復(fù)雜,表數(shù)據(jù)量也越來越大,程序員越來越懶惰,SQL也需要支持非常復(fù)雜的業(yè)務(wù)邏輯,但SQL的性能還需要提高,因此,優(yōu)秀的關(guān)系型數(shù)據(jù)庫除了需要支持復(fù)雜的SQL語法及更多函數(shù)外,還需要有一套優(yōu)秀的算法庫來提高SQL性能。

目前ORACLE有SQL執(zhí)行計劃的算法約300種,而且一直在增加,所以SQL執(zhí)行計劃是一個非常復(fù)雜的課題,一個普通DBA能掌握50種就很不錯了,就算是資深DBA也不可能把每個執(zhí)行計劃的算法描述清楚。雖然有這么多種算法,但并不表示我們無法優(yōu)化執(zhí)行計劃,因為我們常用的SQL執(zhí)行計劃算法也就十幾個,如果一個程序員能把這十幾個算法搞清楚,那就掌握了80%的SQL執(zhí)行計劃調(diào)優(yōu)知識。

由于篇幅的原因,SQL執(zhí)行計劃需要專題介紹,在這里就不多說了。

2、返回更少的數(shù)據(jù)

2.1、數(shù)據(jù)分頁處理

一般數(shù)據(jù)分頁方式有:

2.1.1、客戶端(應(yīng)用程序或瀏覽器)分頁

將數(shù)據(jù)從應(yīng)用服務(wù)器全部下載到本地應(yīng)用程序或瀏覽器,在應(yīng)用程序或瀏覽器內(nèi)部通過本地代碼進(jìn)行分頁處理

優(yōu)點:編碼簡單,減少客戶端與應(yīng)用服務(wù)器網(wǎng)絡(luò)交互次數(shù)

缺點:首次交互時間長,占用客戶端內(nèi)存

適應(yīng)場景:客戶端與應(yīng)用服務(wù)器網(wǎng)絡(luò)延時較大,但要求后續(xù)操作流暢,如手機(jī)GPRS,超遠(yuǎn)程訪問(跨國)等等。

2.1.2、應(yīng)用服務(wù)器分頁

將數(shù)據(jù)從數(shù)據(jù)庫服務(wù)器全部下載到應(yīng)用服務(wù)器,在應(yīng)用服務(wù)器內(nèi)部再進(jìn)行數(shù)據(jù)篩選。以下是一個應(yīng)用服務(wù)器端Java程序分頁的示例:

List list=executeQuery(“select * from employee order by id”);Int count= list.size();List subList= list.subList(10, 20);

優(yōu)點:編碼簡單,只需要一次SQL交互,總數(shù)據(jù)與分頁數(shù)據(jù)差不多時性能較好。

缺點:總數(shù)據(jù)量較多時性能較差。

適應(yīng)場景:數(shù)據(jù)庫系統(tǒng)不支持分頁處理,數(shù)據(jù)量較小并且可控。

2.1.3、數(shù)據(jù)庫SQL分頁

采用數(shù)據(jù)庫SQL分頁需要兩次SQL完成

一個SQL計算總數(shù)量

一個SQL返回分頁后的數(shù)據(jù)

優(yōu)點:性能好

缺點:編碼復(fù)雜,各種數(shù)據(jù)庫語法不同,需要兩次SQL交互。

oracle數(shù)據(jù)庫一般采用rownum來進(jìn)行分頁,常用分頁語法有如下兩種:

直接通過rownum分頁:

select * from ( select a.*,rownum rn from (select * from product a where company_id=? order by status) a where rownum<=20)where rn>10;

數(shù)據(jù)訪問開銷=索引IO+索引全部記錄結(jié)果對應(yīng)的表數(shù)據(jù)IO

采用rowid分頁語法

優(yōu)化原理是通過純索引找出分頁記錄的ROWID,再通過ROWID回表返回數(shù)據(jù),要求內(nèi)層查詢和排序字段全在索引里。

create index myindex on product(company_id,status);select b.* from ( select * from ( select a.*,rownum rn from (select rowid rid,status from product a where company_id=? order by status) a where rownum<=20) where rn>10) a, product bwhere a.rid=b.rowid;

數(shù)據(jù)訪問開銷=索引IO+索引分頁結(jié)果對應(yīng)的表數(shù)據(jù)IO

實例:

一個公司產(chǎn)品有1000條記錄,要分頁取其中20個產(chǎn)品,假設(shè)訪問公司索引需要50個IO,2條記錄需要1個表數(shù)據(jù)IO。

那么按第一種ROWNUM分頁寫法,需要550(50+1000/2)個IO,按第二種ROWID分頁寫法,只需要60個IO(50+20/2);

2.2、只返回需要的字段

通過去除不必要的返回字段可以提高性能,例:

調(diào)整前:select * from product where company_id=?;調(diào)整后:select id,name from product where company_id=?;

優(yōu)點:

1、減少數(shù)據(jù)在網(wǎng)絡(luò)上傳輸開銷

2、減少服務(wù)器數(shù)據(jù)處理開銷

3、減少客戶端內(nèi)存占用

4、字段變更時提前發(fā)現(xiàn)問題,減少程序BUG

5、如果訪問的所有字段剛好在一個索引里面,則可以使用純索引訪問提高性能。

缺點:增加編碼工作量

由于會增加一些編碼工作量,所以一般需求通過開發(fā)規(guī)范來要求程序員這么做,否則等項目上線后再整改工作量更大。

如果你的查詢表中有大字段或內(nèi)容較多的字段,如備注信息、文件內(nèi)容等等,那在查詢表時一定要注意這方面的問題,否則可能會帶來嚴(yán)重的性能問題。如果表經(jīng)常要查詢并且請求大內(nèi)容字段的概率很低,我們可以采用分表處理,將一個大表分拆成兩個一對一的關(guān)系表,將不常用的大內(nèi)容字段放在一張單獨的表中。如一張存儲上傳文件的表:

T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE,FILE_CONTENT)

我們可以分拆成兩張一對一的關(guān)系表:

T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE)

T_FILECONTENT(ID, FILE_CONTENT)

?????????通過這種分拆,可以大大提少T_FILE表的單條記錄及總大小,這樣在查詢T_FILE時性能會更好,當(dāng)需要查詢FILE_CONTENT字段內(nèi)容時再訪問T_FILECONTENT表。

3、減少交互次數(shù)

3.1、batch DML

數(shù)據(jù)庫訪問框架一般都提供了批量提交的接口,jdbc支持batch的提交處理方法,當(dāng)你一次性要往一個表中插入1000萬條數(shù)據(jù)時,如果采用普通的executeUpdate處理,那么和服務(wù)器交互次數(shù)為1000萬次,按每秒鐘可以向數(shù)據(jù)庫服務(wù)器提交10000次估算,要完成所有工作需要1000秒。如果采用批量提交模式,1000條提交一次,那么和服務(wù)器交互次數(shù)為1萬次,交互次數(shù)大大減少。采用batch操作一般不會減少很多數(shù)據(jù)庫服務(wù)器的物理IO,但是會大大減少客戶端與服務(wù)端的交互次數(shù),從而減少了多次發(fā)起的網(wǎng)絡(luò)延時開銷,同時也會降低數(shù)據(jù)庫的CPU開銷。

假設(shè)要向一個普通表插入1000萬數(shù)據(jù),每條記錄大小為1K字節(jié),表上沒有任何索引,客戶端與數(shù)據(jù)庫服務(wù)器網(wǎng)絡(luò)是100Mbps,以下是根據(jù)現(xiàn)在一般計算機(jī)能力估算的各種batch大小性能對比值:

 單位:ms

No batch

Batch=10

Batch=100

Batch=1000

Batch=10000

服務(wù)器事務(wù)處理時間

0.1

0.1

0.1

0.1

0.1

服務(wù)器IO處理時間

0.02

0.2

2

20

200

網(wǎng)絡(luò)交互發(fā)起時間

0.1

0.1

0.1

0.1

0.1

網(wǎng)絡(luò)數(shù)據(jù)傳輸時間

0.01

0.1

1

10

100

小計

0.23

0.5

3.2

30.2

300.2

平均每條記錄處理時間

0.23

0.05

0.032

0.0302

0.03002

從上可以看出,Insert操作加大Batch可以對性能提高近8倍性能,一般根據(jù)主鍵的Update或Delete操作也可能提高2-3倍性能,但不如Insert明顯,因為Update及Delete操作可能有比較大的開銷在物理IO訪問。以上僅是理論計算值,實際情況需要根據(jù)具體環(huán)境測量。

3.2、In List

很多時候我們需要按一些ID查詢數(shù)據(jù)庫記錄,我們可以采用一個ID一個請求發(fā)給數(shù)據(jù)庫,如下所示:

for :var in ids[] do begin select * from mytable where id=:var;end;

我們也可以做一個小的優(yōu)化,?如下所示,用ID INLIST的這種方式寫SQL:

select * from mytable where id in(:id1,id2,...,idn);

通過這樣處理可以大大減少SQL請求的數(shù)量,從而提高性能。那如果有10000個ID,那是不是全部放在一條SQL里處理呢?答案肯定是否定的。首先大部份數(shù)據(jù)庫都會有SQL長度和IN里個數(shù)的限制,如ORACLE的IN里就不允許超過1000個值。

另外當(dāng)前數(shù)據(jù)庫一般都是采用基于成本的優(yōu)化規(guī)則,當(dāng)IN數(shù)量達(dá)到一定值時有可能改變SQL執(zhí)行計劃,從索引訪問變成全表訪問,這將使性能急劇變化。隨著SQL中IN的里面的值個數(shù)增加,SQL的執(zhí)行計劃會更復(fù)雜,占用的內(nèi)存將會變大,這將會增加服務(wù)器CPU及內(nèi)存成本。

評估在IN里面一次放多少個值還需要考慮應(yīng)用服務(wù)器本地內(nèi)存的開銷,有并發(fā)訪問時要計算本地數(shù)據(jù)使用周期內(nèi)的并發(fā)上限,否則可能會導(dǎo)致內(nèi)存溢出。

綜合考慮,一般IN里面的值個數(shù)超過20個以后性能基本沒什么太大變化,也特別說明不要超過100,超過后可能會引起執(zhí)行計劃的不穩(wěn)定性及增加數(shù)據(jù)庫CPU及內(nèi)存成本,這個需要專業(yè)DBA評估。

3.3、設(shè)置Fetch Size

當(dāng)我們采用select從數(shù)據(jù)庫查詢數(shù)據(jù)時,數(shù)據(jù)默認(rèn)并不是一條一條返回給客戶端的,也不是一次全部返回客戶端的,而是根據(jù)客戶端fetch_size參數(shù)處理,每次只返回fetch_size條記錄,當(dāng)客戶端游標(biāo)遍歷到尾部時再從服務(wù)端取數(shù)據(jù),直到最后全部傳送完成。所以如果我們要從服務(wù)端一次取大量數(shù)據(jù)時,可以加大fetch_size,這樣可以減少結(jié)果數(shù)據(jù)傳輸?shù)慕换ゴ螖?shù)及服務(wù)器數(shù)據(jù)準(zhǔn)備時間,提高性能。

以下是jdbc測試的代碼,采用本地數(shù)據(jù)庫,表緩存在數(shù)據(jù)庫CACHE中,因此沒有網(wǎng)絡(luò)連接及磁盤IO開銷,客戶端只遍歷游標(biāo),不做任何處理,這樣更能體現(xiàn)fetch參數(shù)的影響:

String vsql ="select * from t_employee";PreparedStatement pstmt = conn.prepareStatement(vsql,ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);pstmt.setFetchSize(1000);ResultSet rs = pstmt.executeQuery(vsql);int cnt = rs.getMetaData().getColumnCount();Object o;while (rs.next()) { for (int i = 1; i <= cnt; i++) { o = rs.getObject(i); }}

測試示例中的employee表有100000條記錄,每條記錄平均長度135字節(jié)

以下是測試結(jié)果,對每種fetchsize測試5次再取平均值:

fetchsize

?elapse_time(s)

1

20.516

2

11.34

4

6.894

8

4.65

16

3.584

32

2.865

64

2.656

128

2.44

256

2.765

512

3.075

1024

2.862

2048

2.722

4096

2.681

8192

2.715

Oracle jdbc fetchsize默認(rèn)值為10,由上測試可以看出fetchsize對性能影響還是比較大的,但是當(dāng)fetchsize大于100時就基本上沒有影響了。fetchsize并不會存在一個最優(yōu)的固定值,因為整體性能與記錄集大小及硬件平臺有關(guān)。根據(jù)測試結(jié)果建議當(dāng)一次性要取大量數(shù)據(jù)時這個值設(shè)置為100左右,不要小于40。注意,fetchsize不能設(shè)置太大,如果一次取出的數(shù)據(jù)大于JVM的內(nèi)存會導(dǎo)致內(nèi)存溢出,所以建議不要超過1000,太大了也沒什么性能提高,反而可能會增加內(nèi)存溢出的危險。

注:圖中fetchsize在128以后會有一些小的波動,這并不是測試誤差,而是由于resultset填充到具體對像時間不同的原因,由于resultset已經(jīng)到本地內(nèi)存里了,所以估計是由于CPU的L1,L2 Cache命中率變化造成,由于變化不大,所以筆者也未深入分析原因。

iBatis的SqlMapping配置文件可以對每個SQL語句指定fetchsize大小,如下所示:

<select id="getAllProduct" resultMap="HashMap" fetchSize="1000">select * from employeeselect>

3.4、使用存儲過程

大型數(shù)據(jù)庫一般都支持存儲過程,合理的利用存儲過程也可以提高系統(tǒng)性能。如你有一個業(yè)務(wù)需要將A表的數(shù)據(jù)做一些加工然后更新到B表中,但是又不可能一條SQL完成,這時你需要如下3步操作:

a:將A表數(shù)據(jù)全部取出到客戶端;

b:計算出要更新的數(shù)據(jù);

c:將計算結(jié)果更新到B表。

如果采用存儲過程你可以將整個業(yè)務(wù)邏輯封裝在存儲過程里,然后在客戶端直接調(diào)用存儲過程處理,這樣可以減少網(wǎng)絡(luò)交互的成本。

當(dāng)然,存儲過程也并不是十全十美,存儲過程有以下缺點:

a、不可移植性,每種數(shù)據(jù)庫的內(nèi)部編程語法都不太相同,當(dāng)你的系統(tǒng)需要兼容多種數(shù)據(jù)庫時最好不要用存儲過程。

b、學(xué)習(xí)成本高,DBA一般都擅長寫存儲過程,但并不是每個程序員都能寫好存儲過程,除非你的團(tuán)隊有較多的開發(fā)人員熟悉寫存儲過程,否則后期系統(tǒng)維護(hù)會產(chǎn)生問題。

c、業(yè)務(wù)邏輯多處存在,采用存儲過程后也就意味著你的系統(tǒng)有一些業(yè)務(wù)邏輯不是在應(yīng)用程序里處理,這種架構(gòu)會增加一些系統(tǒng)維護(hù)和調(diào)試成本。

d、存儲過程和常用應(yīng)用程序語言不一樣,它支持的函數(shù)及語法有可能不能滿足需求,有些邏輯就只能通過應(yīng)用程序處理。

e、如果存儲過程中有復(fù)雜運(yùn)算的話,會增加一些數(shù)據(jù)庫服務(wù)端的處理成本,對于集中式數(shù)據(jù)庫可能會導(dǎo)致系統(tǒng)可擴(kuò)展性問題。

f、為了提高性能,數(shù)據(jù)庫會把存儲過程代碼編譯成中間運(yùn)行代碼(類似于java的class文件),所以更像靜態(tài)語言。當(dāng)存儲過程引用的對像(表、視圖等等)結(jié)構(gòu)改變后,存儲過程需要重新編譯才能生效,在24*7高并發(fā)應(yīng)用場景,一般都是在線變更結(jié)構(gòu)的,所以在變更的瞬間要同時編譯存儲過程,這可能會導(dǎo)致數(shù)據(jù)庫瞬間壓力上升引起故障(Oracle數(shù)據(jù)庫就存在這樣的問題)。

個人觀點:普通業(yè)務(wù)邏輯盡量不要使用存儲過程,定時性的ETL任務(wù)或報表統(tǒng)計函數(shù)可以根據(jù)團(tuán)隊資源情況采用存儲過程處理。

3.5、優(yōu)化業(yè)務(wù)邏輯

要通過優(yōu)化業(yè)務(wù)邏輯來提高性能是比較困難的,這需要程序員對所訪問的數(shù)據(jù)及業(yè)務(wù)流程非常清楚。

舉一個案例:

某移動公司推出優(yōu)惠套參,活動對像為VIP會員并且2010年1,2,3月平均話費20元以上的客戶。

那我們的檢測邏輯為:

select avg(money) as avg_money from bill where phone_no='13988888888' and date between '201001' and '201003';select vip_flag from member where phone_no='13988888888';if avg_money>20 and vip_flag=true thenbegin 執(zhí)行套參();end;

如果我們修改業(yè)務(wù)邏輯為:

select avg(money) as avg_money from bill where phone_no='13988888888' and date between '201001' and '201003';if avg_money>20 thenbegin select vip_flag from member where phone_no='13988888888'; if vip_flag=true then begin 執(zhí)行套參(); end;end;

通過這樣可以減少一些判斷vip_flag的開銷,平均話費20元以下的用戶就不需要再檢測是否VIP了。

如果程序員分析業(yè)務(wù),VIP會員比例為1%,平均話費20元以上的用戶比例為90%,那我們改成如下:

select vip_flag from member where phone_no='13988888888';if vip_flag=true thenbegin select avg(money) as avg_money from bill where phone_no='13988888888' and date between '201001' and '201003'; if avg_money>20 then begin 執(zhí)行套參(); end;end;

這樣就只有1%的VIP會員才會做檢測平均話費,最終大大減少了SQL的交互次數(shù)。

以上只是一個簡單的示例,實際的業(yè)務(wù)總是比這復(fù)雜得多,所以一般只是高級程序員更容易做出優(yōu)化的邏輯,但是我們需要有這樣一種成本優(yōu)化的意識。

3.6、使用ResultSet游標(biāo)處理記錄

現(xiàn)在大部分Java框架都是通過jdbc從數(shù)據(jù)庫取出數(shù)據(jù),然后裝載到一個list里再處理,list里可能是業(yè)務(wù)Object,也可能是hashmap。

由于JVM內(nèi)存一般都小于4G,所以不可能一次通過sql把大量數(shù)據(jù)裝載到list里。為了完成功能,很多程序員喜歡采用分頁的方法處理,如一次從數(shù)據(jù)庫取1000條記錄,通過多次循環(huán)搞定,保證不會引起JVM Out of memory問題。

以下是實現(xiàn)此功能的代碼示例,t_employee表有10萬條記錄,設(shè)置分頁大小為1000:

d1 = Calendar.getInstance().getTime();vsql = "select count(*) cnt from t_employee";pstmt = conn.prepareStatement(vsql);ResultSet rs = pstmt.executeQuery();Integer cnt = 0;while (rs.next()) { cnt = rs.getInt("cnt");}Integer lastid=0;Integer pagesize=1000;System.out.println("cnt:" + cnt);String vsql = "select count(*) cnt from t_employee";PreparedStatement pstmt = conn.prepareStatement(vsql);ResultSet rs = pstmt.executeQuery();Integer cnt = 0;while (rs.next()) { cnt = rs.getInt("cnt");}Integer lastid = 0;Integer pagesize = 1000;System.out.println("cnt:" + cnt);for (int i = 0; i <= cnt / pagesize; i++) { vsql = "select * from (select * from t_employee where id>? order by id) where rownum<=?"; pstmt = conn.prepareStatement(vsql); pstmt.setFetchSize(1000); pstmt.setInt(1, lastid); pstmt.setInt(2, pagesize); rs = pstmt.executeQuery(); int col_cnt = rs.getMetaData().getColumnCount(); Object o; while (rs.next()) { for (int j = 1; j <= col_cnt; j++) { o = rs.getObject(j); } lastid = rs.getInt("id"); } rs.close(); pstmt.close();}

以上代碼實際執(zhí)行時間為6.516秒

很多持久層框架為了盡量讓程序員使用方便,封裝了jdbc通過statement執(zhí)行數(shù)據(jù)返回到resultset的細(xì)節(jié),導(dǎo)致程序員會想采用分頁的方式處理問題。實際上如果我們采用jdbc原始的resultset游標(biāo)處理記錄,在resultset循環(huán)讀取的過程中處理記錄,這樣就可以一次從數(shù)據(jù)庫取出所有記錄。顯著提高性能。

這里需要注意的是,采用resultset游標(biāo)處理記錄時,應(yīng)該將游標(biāo)的打開方式設(shè)置為FORWARD_READONLY模式(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY),否則會把結(jié)果緩存在JVM里,造成JVM Out of memory問題。

代碼示例:

String vsql ="select * from t_employee";PreparedStatement pstmt = conn.prepareStatement(vsql,ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);pstmt.setFetchSize(100);ResultSet rs = pstmt.executeQuery(vsql);int col_cnt = rs.getMetaData().getColumnCount();Object o;while (rs.next()) { for (int j = 1; j <= col_cnt; j++) { o = rs.getObject(j); }}

調(diào)整后的代碼實際執(zhí)行時間為3.156秒

從測試結(jié)果可以看出性能提高了1倍多,如果采用分頁模式數(shù)據(jù)庫每次還需發(fā)生磁盤IO的話那性能可以提高更多。

iBatis等持久層框架考慮到會有這種需求,所以也有相應(yīng)的解決方案,在iBatis里我們不能采用queryForList的方法,而應(yīng)用該采用queryWithRowHandler加回調(diào)事件的方式處理,如下所示:

MyRowHandler myrh=new MyRowHandler();sqlmap.queryWithRowHandler("getAllEmployee", myrh);class MyRowHandler implements RowHandler { public void handleRow(Object o) { //todo something }}

iBatis的queryWithRowHandler很好的封裝了resultset遍歷的事件處理,效果及性能與resultset遍歷一樣,也不會產(chǎn)生JVM內(nèi)存溢出。

4、減少數(shù)據(jù)庫服務(wù)器CPU運(yùn)算

4.1、使用綁定變量

綁定變量是指SQL中對變化的值采用變量參數(shù)的形式提交,而不是在SQL中直接拼寫對應(yīng)的值。

非綁定變量寫法:

Select * from employee where id=1234567

綁定變量寫法:

Select * from employee where id=?Preparestatement.setInt(1,1234567)

Java中Preparestatement就是為處理綁定變量提供的對像,綁定變量有以下優(yōu)點:

1、防止SQL注入

2、提高SQL可讀性

3、提高SQL解析性能,不使用綁定變更我們一般稱為硬解析,使用綁定變量我們稱為軟解析。

第1和第2點很好理解,做編碼的人應(yīng)該都清楚,這里不詳細(xì)說明。關(guān)于第3點,到底能提高多少性能呢,下面舉一個例子說明:

假設(shè)有這個這樣的一個數(shù)據(jù)庫主機(jī):

2個4核CPU?

100塊磁盤,每個磁盤支持IOPS為160

業(yè)務(wù)應(yīng)用的SQL如下:

select * from table where pk=?

這個SQL平均4個IO(3個索引IO+1個數(shù)據(jù)IO)

IO緩存命中率75%(索引全在內(nèi)存中,數(shù)據(jù)需要訪問磁盤)

SQL硬解析CPU消耗:1ms ?(常用經(jīng)驗值)

SQL軟解析CPU消耗:0.02ms(常用經(jīng)驗值)

假設(shè)CPU每核性能是線性增長,訪問內(nèi)存Cache中的IO時間忽略,要求計算系統(tǒng)對如上應(yīng)用采用硬解析與采用軟解析支持的每秒最大并發(fā)數(shù):

是否使用綁定變量

CPU支持最大并發(fā)數(shù)

磁盤IO支持最大并發(fā)數(shù)

不使用

2*4*1000=8000

100*160=16000

使用

2*4*1000/0.02=400000

100*160=16000

從以上計算可以看出,不使用綁定變量的系統(tǒng)當(dāng)并發(fā)達(dá)到8000時會在CPU上產(chǎn)生瓶頸,當(dāng)使用綁定變量的系統(tǒng)當(dāng)并行達(dá)到16000時會在磁盤IO上產(chǎn)生瓶頸。所以如果你的系統(tǒng)CPU有瓶頸時請先檢查是否存在大量的硬解析操作。

使用綁定變量為何會提高SQL解析性能,這個需要從數(shù)據(jù)庫SQL執(zhí)行原理說明,一條SQL在Oracle數(shù)據(jù)庫中的執(zhí)行過程如下圖所示:

當(dāng)一條SQL發(fā)送給數(shù)據(jù)庫服務(wù)器后,系統(tǒng)首先會將SQL字符串進(jìn)行hash運(yùn)算,得到hash值后再從服務(wù)器內(nèi)存里的SQL緩存區(qū)中進(jìn)行檢索,如果有相同的SQL字符,并且確認(rèn)是同一邏輯的SQL語句,則從共享池緩存中取出SQL對應(yīng)的執(zhí)行計劃,根據(jù)執(zhí)行計劃讀取數(shù)據(jù)并返回結(jié)果給客戶端。

如果在共享池中未發(fā)現(xiàn)相同的SQL則根據(jù)SQL邏輯生成一條新的執(zhí)行計劃并保存在SQL緩存區(qū)中,然后根據(jù)執(zhí)行計劃讀取數(shù)據(jù)并返回結(jié)果給客戶端。

為了更快的檢索SQL是否在緩存區(qū)中,首先進(jìn)行的是SQL字符串hash值對比,如果未找到則認(rèn)為沒有緩存,如果存在再進(jìn)行下一步的準(zhǔn)確對比,所以要命中SQL緩存區(qū)應(yīng)保證SQL字符是完全一致,中間有大小寫或空格都會認(rèn)為是不同的SQL。

如果我們不采用綁定變量,采用字符串拼接的模式生成SQL,那么每條SQL都會產(chǎn)生執(zhí)行計劃,這樣會導(dǎo)致共享池耗盡,緩存命中率也很低。

一些不使用綁定變量的場景:

a、數(shù)據(jù)倉庫應(yīng)用,這種應(yīng)用一般并發(fā)不高,但是每個SQL執(zhí)行時間很長,SQL解析的時間相比SQL執(zhí)行時間比較小,綁定變量對性能提高不明顯。數(shù)據(jù)倉庫一般都是內(nèi)部分析應(yīng)用,所以也不太會發(fā)生SQL注入的安全問題。

b、數(shù)據(jù)分布不均勻的特殊邏輯,如產(chǎn)品表,記錄有1億,有一產(chǎn)品狀態(tài)字段,上面建有索引,有審核中,審核通過,審核未通過3種狀態(tài),其中審核通過9500萬,審核中1萬,審核不通過499萬。

要做這樣一個查詢:

select count(*) from product where status=?

采用綁定變量的話,那么只會有一個執(zhí)行計劃,如果走索引訪問,那么對于審核中查詢很快,對審核通過和審核不通過會很慢;如果不走索引,那么對于審核中與審核通過和審核不通過時間基本一樣;

對于這種情況應(yīng)該不使用綁定變量,而直接采用字符拼接的方式生成SQL,這樣可以為每個SQL生成不同的執(zhí)行計劃,如下所示。

select count(*) from product where status='approved'; //不使用索引select count(*) from product where status='tbd'; //不使用索引select count(*) from product where status='auditing';//使用索引

4.2、合理使用排序

Oracle的排序算法一直在優(yōu)化,但是總體時間復(fù)雜度約等于nLog(n)。普通OLTP系統(tǒng)排序操作一般都是在內(nèi)存里進(jìn)行的,對于數(shù)據(jù)庫來說是一種CPU的消耗,曾在PC機(jī)做過測試,單核普通CPU在1秒鐘可以完成100萬條記錄的全內(nèi)存排序操作,所以說由于現(xiàn)在CPU的性能增強(qiáng),對于普通的幾十條或上百條記錄排序?qū)ο到y(tǒng)的影響也不會很大。但是當(dāng)你的記錄集增加到上萬條以上時,你需要注意是否一定要這么做了,大記錄集排序不僅增加了CPU開銷,而且可能會由于內(nèi)存不足發(fā)生硬盤排序的現(xiàn)象,當(dāng)發(fā)生硬盤排序時性能會急劇下降,這種需求需要與DBA溝通再決定,取決于你的需求和數(shù)據(jù),所以只有你自己最清楚,而不要被別人說排序很慢就嚇倒。

以下列出了可能會發(fā)生排序操作的SQL語法:

Order by

Group by

Distinct

Exists子查詢

Not Exists子查詢

In子查詢

Not In子查詢

Union(并集),Union All也是一種并集操作,但是不會發(fā)生排序,如果你確認(rèn)兩個數(shù)據(jù)集不需要執(zhí)行去除重復(fù)數(shù)據(jù)操作,那請使用Union All 代替Union。

Minus(差集)

Intersect(交集)

Create Index

Merge Join,這是一種兩個表連接的內(nèi)部算法,執(zhí)行時會把兩個表先排序好再連接,應(yīng)用于兩個大表連接的操作。如果你的兩個表連接的條件都是等值運(yùn)算,那可以采用Hash Join來提高性能,因為Hash Join使用Hash 運(yùn)算來代替排序的操作。具體原理及設(shè)置參考SQL執(zhí)行計劃優(yōu)化專題。

4.3、減少比較操作

我們SQL的業(yè)務(wù)邏輯經(jīng)常會包含一些比較操作,如a=b,a

Like模糊查詢,如下所示:

a like ‘%abc%’

Like模糊查詢對于數(shù)據(jù)庫來說不是很擅長,特別是你需要模糊檢查的記錄有上萬條以上時,性能比較糟糕,這種情況一般可以采用專用Search或者采用全文索引方案來提高性能。

不能使用索引定位的大量In List,如下所示:

a in (:1,:2,:3,…,:n)???----n>20

如果這里的a字段不能通過索引比較,那數(shù)據(jù)庫會將字段與in里面的每個值都進(jìn)行比較運(yùn)算,如果記錄數(shù)有上萬以上,會明顯感覺到SQL的CPU開銷加大,這個情況有兩種解決方式:

a、??將in列表里面的數(shù)據(jù)放入一張中間小表,采用兩個表Hash Join關(guān)聯(lián)的方式處理;

b、??采用str2varList方法將字段串列表轉(zhuǎn)換一個臨時表處理,關(guān)于str2varList方法可以在網(wǎng)上直接查詢,這里不詳細(xì)介紹。

以上兩種解決方案都需要與中間表Hash Join的方式才能提高性能,如果采用了Nested Loop的連接方式性能會更差。

如果發(fā)現(xiàn)我們的系統(tǒng)IO沒問題但是CPU負(fù)載很高,就有可能是上面的原因,這種情況不太常見,如果遇到了最好能和DBA溝通并確認(rèn)準(zhǔn)確的原因。

4.4、大量復(fù)雜運(yùn)算在客戶端處理

什么是復(fù)雜運(yùn)算,一般我認(rèn)為是一秒鐘CPU只能做10萬次以內(nèi)的運(yùn)算。如含小數(shù)的對數(shù)及指數(shù)運(yùn)算、三角函數(shù)、3DES及BASE64數(shù)據(jù)加密算法等等。

如果有大量這類函數(shù)運(yùn)算,盡量放在客戶端處理,一般CPU每秒中也只能處理1萬-10萬次這樣的函數(shù)運(yùn)算,放在數(shù)據(jù)庫內(nèi)不利于高并發(fā)處理。

5、利用更多的資源

5.1、客戶端多進(jìn)程并行訪問

多進(jìn)程并行訪問是指在客戶端創(chuàng)建多個進(jìn)程(線程),每個進(jìn)程建立一個與數(shù)據(jù)庫的連接,然后同時向數(shù)據(jù)庫提交訪問請求。當(dāng)數(shù)據(jù)庫主機(jī)資源有空閑時,我們可以采用客戶端多進(jìn)程并行訪問的方法來提高性能。如果數(shù)據(jù)庫主機(jī)已經(jīng)很忙時,采用多進(jìn)程并行訪問性能不會提高,反而可能會更慢。所以使用這種方式最好與DBA或系統(tǒng)管理員進(jìn)行溝通后再決定是否采用。

例如:

我們有10000個產(chǎn)品ID,現(xiàn)在需要根據(jù)ID取出產(chǎn)品的詳細(xì)信息,如果單線程訪問,按每個IO要5ms計算,忽略主機(jī)CPU運(yùn)算及網(wǎng)絡(luò)傳輸時間,我們需要50s才能完成任務(wù)。如果采用5個并行訪問,每個進(jìn)程訪問2000個ID,那么10s就有可能完成任務(wù)。

那是不是并行數(shù)越多越好呢,開1000個并行是否只要50ms就搞定,答案肯定是否定的,當(dāng)并行數(shù)超過服務(wù)器主機(jī)資源的上限時性能就不會再提高,如果再增加反而會增加主機(jī)的進(jìn)程間調(diào)度成本和進(jìn)程沖突機(jī)率。

以下是一些如何設(shè)置并行數(shù)的基本建議:

如果瓶頸在服務(wù)器主機(jī),但是主機(jī)還有空閑資源,那么最大并行數(shù)取主機(jī)CPU核數(shù)和主機(jī)提供數(shù)據(jù)服務(wù)的磁盤數(shù)兩個參數(shù)中的最小值,同時要保證主機(jī)有資源做其它任務(wù)。

如果瓶頸在客戶端處理,但是客戶端還有空閑資源,那建議不要增加SQL的并行,而是用一個進(jìn)程取回數(shù)據(jù)后在客戶端起多個進(jìn)程處理即可,進(jìn)程數(shù)根據(jù)客戶端CPU核數(shù)計算。

如果瓶頸在客戶端網(wǎng)絡(luò),那建議做數(shù)據(jù)壓縮或者增加多個客戶端,采用map reduce的架構(gòu)處理。

如果瓶頸在服務(wù)器網(wǎng)絡(luò),那需要增加服務(wù)器的網(wǎng)絡(luò)帶寬或者在服務(wù)端將數(shù)據(jù)壓縮后再處理了。

5.2、數(shù)據(jù)庫并行處理

數(shù)據(jù)庫并行處理是指客戶端一條SQL的請求,數(shù)據(jù)庫內(nèi)部自動分解成多個進(jìn)程并行處理,如下圖所示:

并不是所有的SQL都可以使用并行處理,一般只有對表或索引進(jìn)行全部訪問時才可以使用并行。數(shù)據(jù)庫表默認(rèn)是不打開并行訪問,所以需要指定SQL并行的提示,如下所示:

select?/*+parallel(a,4)*/?* from employee;

并行的優(yōu)點:

使用多進(jìn)程處理,充分利用數(shù)據(jù)庫主機(jī)資源(CPU,IO),提高性能。

并行的缺點:

1、單個會話占用大量資源,影響其它會話,所以只適合在主機(jī)負(fù)載低時期使用;

2、只能采用直接IO訪問,不能利用緩存數(shù)據(jù),所以執(zhí)行前會觸發(fā)將臟緩存數(shù)據(jù)寫入磁盤操作。

注:

1、并行處理在OLTP類系統(tǒng)中慎用,使用不當(dāng)會導(dǎo)致一個會話把主機(jī)資源全部占用,而正常事務(wù)得不到及時響應(yīng),所以一般只是用于數(shù)據(jù)倉庫平臺。

2、一般對于百萬級記錄以下的小表采用并行訪問性能并不能提高,反而可能會讓性能更差。

參考文章:

http://www.cnblogs.com/easypass/archive/2010/12/08/1900127.html

http://www.cnblogs.com/yunfeifei/p/3850440.html

End

猜你喜歡:

SQL人的優(yōu)勢:實戰(zhàn)大數(shù)據(jù)開發(fā)10分鐘入門

完成一次簡單的 SQL 注入

2019 MySQL8 24小時快速入門(3)

2019 MySQL8 24小時快速入門(2)

2019 MySQL8 24小時快速入門(1)

總結(jié)

以上是生活随笔為你收集整理的oracle in 索引_Oracle 性能优化总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

99av国产精品欲麻豆 | 亚洲一区二区三区毛片 | 色偷偷中文字幕 | 国产精品视频区 | 久久最新视频 | 国产免费嫩草影院 | 日韩激情视频在线观看 | 亚洲永久精品在线观看 | 国产精品久久婷婷六月丁香 | www.久久99| 国产精品麻豆视频 | 久久超碰网 | 亚洲精选国产 | 国产精品久久久久一区二区国产 | av网站免费线看精品 | 香蕉视频91| 亚洲国产精品小视频 | 黄色a在线观看 | 一区二区不卡 | 88av视频 | 日本丰满少妇免费一区 | 亚洲黄色一级大片 | 国产真实在线 | 欧美三级高清 | 国产日韩欧美视频在线观看 | 欧美作爱视频 | 97超碰国产精品 | 欧美日韩电影在线播放 | 不卡视频一区二区三区 | 在线电影91 | 精品免费国产一区二区三区四区 | 99性视频 | 玖玖爱免费视频 | 精品久久久久久久久久国产 | 99热在 | aaa毛片视频 | 91av在 | 午夜电影av | 99久久精品国产亚洲 | 99在线播放 | 在线看国产日韩 | 狠狠黄 | 久久精品国产精品亚洲精品 | 在线91av| 日韩三级成人 | 精品a视频 | 国产精品igao视频网网址 | 免费观看黄| 免费在线播放 | 亚洲综合精品在线 | 久久久免费在线观看 | 国产精品九九九九九 | 欧美日韩国产在线精品 | 九色91视频| 色婷婷综合久久久久中文字幕1 | 天天插综合网 | 成年人免费在线 | 天天天天天天天天操 | 69绿帽绿奴3pvideos | 97免费在线观看 | 色九九影院 | 天天色天| 久久一区国产 | 天天爽夜夜操 | 久草在线在线视频 | 国产精品久久久久久久久搜平片 | 国产一级黄色av | 亚洲日b视频 | 精品国产美女 | 免费福利在线 | 婷婷激情综合网 | 婷婷伊人综合 | 久久久午夜精品理论片中文字幕 | 五月香视频在线观看 | 精品日韩在线一区 | 欧美日韩另类视频 | 亚洲人成在线电影 | 夜又临在线观看 | 欧美精品视| 国产一区二区高清 | 西西444www大胆高清图片 | 在线黄频 | 国产精品99蜜臀久久不卡二区 | 亚洲成人精品在线 | 国产精品网红直播 | 在线亚洲播放 | 97超碰国产精品女人人人爽 | 精品国产久 | 欧美激情精品久久久久久变态 | 精品黄色在线 | 少妇av网| 国产精品亚洲视频 | 人人插人人插 | 国产高清av | 黄污视频大全 | 99999精品视频| 蜜臀av性久久久久av蜜臀妖精 | 在线日本看片免费人成视久网 | 人人爱爱人人 | 91在线精品秘密一区二区 | av在线网站免费观看 | 久久中文字幕导航 | 亚洲激情影院 | 久久久www成人免费毛片麻豆 | 欧美99热 | 伊人天天狠天天添日日拍 | 精品免费视频. | 国产特级毛片aaaaaa毛片 | 又紧又大又爽精品一区二区 | 亚洲黄色一级大片 | 久久久久久影视 | 国产91亚洲精品 | 国产精品毛片一区视频播不卡 | 五月综合激情 | 91av在线精品| 2020天天干夜夜爽 | 久久成人麻豆午夜电影 | 亚洲精品国偷拍自产在线观看蜜桃 | 免费观看91视频 | 亚洲伊人成综合网 | 91在线porny国产在线看 | 青青河边草手机免费 | 天天亚洲 | 丁香网婷婷 | 亚洲另类视频在线观看 | 美女国内精品自产拍在线播放 | 欧美日韩一区二区在线观看 | 99tvdz@gmail.com| 四虎影视久久久 | 丁香婷五月 | 亚洲精品国产高清 | 中文字幕文字幕一区二区 | 97精品久久人人爽人人爽 | 天天插天天 | av黄色影院 | 亚洲国产成人在线观看 | 久久免费高清 | 欧美黑人巨大xxxxx | 麻豆国产电影 | 中文字幕亚洲欧美日韩 | 日本精品久久久久久 | 手机av在线网站 | 成年人在线电影 | 久久99深爱久久99精品 | 日韩免费在线视频观看 | 久久成人麻豆午夜电影 | 久久不见久久见免费影院 | 精品国产一区二区在线 | 999久久久久久久久6666 | 激情久久久久久久久久久久久久久久 | 免费看麻豆 | 正在播放一区二区 | 成人免费观看电影 | 视频在线播放国产 | 国产日韩精品一区二区三区 | 久草免费在线 | 国产精品久久在线观看 | www夜夜操 | 久久这里只精品 | 在线观看视频在线观看 | 国产精品一区二区吃奶在线观看 | 亚洲欧洲精品一区二区精品久久久 | 青青草华人在线视频 | 亚洲精品日韩在线观看 | 中文高清av | 三级黄色三级 | 日本高清xxxx | 美女av免费看 | 天天综合网久久 | 伊人视频 | 亚洲aⅴ乱码精品成人区 | 国产精品com| 欧美日韩精品在线 | 亚洲最大激情中文字幕 | 国产a级免费 | 国产成人一区二 | 男女激情免费网站 | 国产精品久免费的黄网站 | 九九免费在线视频 | 在线观看不卡的av | 久精品视频在线观看 | www五月天婷婷 | zzijzzij亚洲日本少妇熟睡 | 欧美在线视频一区二区三区 | 在线观看成人av | 成人免费在线播放视频 | 久久综合九色欧美综合狠狠 | 一区国产精品 | 亚洲欧美成aⅴ人在线观看 四虎在线观看 | 亚洲伦理一区 | 亚洲va欧美va人人爽春色影视 | 美女黄频免费 | 久久成人综合视频 | 国产午夜精品免费一区二区三区视频 | 欧美狠狠色 | av黄色国产 | 日韩av一区二区在线播放 | 最新不卡av | 五月天天色| 五月天开心 | 玖玖玖在线观看 | 日韩视频在线不卡 | 丁香花中文在线免费观看 | 亚洲精品视频网站在线观看 | 色婷婷激婷婷情综天天 | 99精品欧美一区二区三区黑人哦 | 波多野结衣久久资源 | 久热色超碰 | 亚洲视频在线观看免费 | 日韩色在线观看 | 超碰国产在线观看 | 伊人中文在线 | 一本一本久久a久久精品综合小说 | 成人黄色影片在线 | 亚洲精品97| 成人免费观看a | 日韩在线视频网 | 国产精品区一区 | 国产精品原创av片国产免费 | 久久免费视频一区 | 色播五月婷婷 | 久久99国产综合精品免费 | 亚州精品成人 | 就操操久久 | 人人爽人人澡人人添人人人人 | 日韩中文幕| 最新日本中文字幕 | 日韩久久久久久久久 | 日韩精品一区二区三区中文字幕 | 国内精品久久久久久久97牛牛 | 极品嫩模被强到高潮呻吟91 | 丁香在线| 99麻豆久久久国产精品免费 | 久久视频国产精品免费视频在线 | 亚洲精品综合在线观看 | 99国产免费网址 | 婷婷综合电影 | a级国产乱理伦片在线观看 亚洲3级 | a√资源在线 | 日本性生活免费看 | 免费日韩三级 | 国产精品亚州 | 色播五月激情综合网 | 久久97久久97精品免视看 | 国产亚洲精品久久久久久网站 | 免费在线观看成人小视频 | 碰超在线观看 | 99精品久久久久久久久久综合 | av亚洲产国偷v产偷v自拍小说 | 欧美精品久久久久久久免费 | 公开超碰在线 | 成人视屏免费看 | 看全黄大色黄大片 | 国产午夜三级一二三区 | 久久久高清一区二区三区 | 国产又粗又硬又长又爽的视频 | 91视频在线看 | av黄色免费在线观看 | 久久久国产精品网站 | 国产黄色免费电影 | 国内外成人在线 | 国产在线播放一区二区三区 | 在线精品在线 | 美女免费视频观看网站 | 国产精品一区二区62 | 99国产情侣在线播放 | 91视频国产免费 | 亚洲电影影音先锋 | 国产乱对白刺激视频在线观看女王 | 精品视频中文字幕 | 欧美大码xxxx | 人人精品久久 | 色婷婷亚洲 | 国产一区二区在线精品 | 激情久久综合 | 激情综合亚洲 | 九九热免费在线观看 | 五月婷婷黄色网 | 亚洲天堂在线观看完整版 | 国产小视频福利在线 | 色九九视频 | 深夜福利视频在线观看 | 97电影在线观看 | 美女久久一区 | 国内精品中文字幕 | www.久艹 | 不卡的av在线 | 国产亚洲精品成人av久久ww | 九色精品免费永久在线 | www国产亚洲精品久久网站 | 国产一区高清在线 | 麻豆 free xxxx movies hd| 免费在线观看午夜视频 | 在线成人小视频 | 深爱五月激情五月 | 国产亚洲精品xxoo | 在线播放视频一区 | 91九色综合 | 欧美色久 | 亚洲美女免费精品视频在线观看 | 天天操福利视频 | 精品国产一区二区三区久久影院 | 在线精品国产 | 综合网伊人 | 成片免费观看视频999 | 色在线国产 | 婷色在线 | 一级黄色大片 | 黄色午夜网站 | 国产中出在线观看 | 国产精品中文字幕在线观看 | 伊人六月 | 亚洲激情久久 | 91中文在线 | 久草在线网址 | 99免费| 国产五码一区 | a天堂最新版中文在线地址 久久99久久精品国产 | 亚洲精品小视频在线观看 | 日本高清中文字幕有码在线 | 伊人天堂久久 | 六月丁香六月婷婷 | 日韩黄色一区 | 国产精品 欧美 日韩 | 国产激情久久久 | 国产色在线视频 | 日韩精品一二三 | 国产人成看黄久久久久久久久 | 成人av中文字幕在线观看 | 亚洲一区网 | 久久国产精品久久久久 | 97在线观看免费观看高清 | www.香蕉视频在线观看 | 一级久久精品 | 久久免费视频精品 | 久精品在线观看 | 免费三级大片 | 久草在线99 | 免费成人在线视频网站 | 96国产精品视频 | 亚洲国产精品推荐 | 亚洲精品国偷拍自产在线观看蜜桃 | 夜夜夜夜猛噜噜噜噜噜初音未来 | wwwav视频 | 国产色一区 | 亚洲三级国产 | 国产手机av在线 | 亚洲理论电影网 | 欧美不卡视频在线 | 天天插天天狠 | 91大神电影 | 亚洲精品玖玖玖av在线看 | 亚洲最大激情中文字幕 | 亚洲女欲精品久久久久久久18 | 少妇bbw搡bbbb搡bbb | 亚洲精品久久久久999中文字幕 | 国产一级视频免费看 | 久久久综合九色合综国产精品 | 午夜精品久久久久久久99 | 日韩成人精品 | 久久这里只有精品23 | 91高清一区 | 久久久精品国产免费观看一区二区 | 免费视频久久久 | 日本在线视频一区二区三区 | 日韩视频一区二区在线 | 成 人 黄 色视频免费播放 | 日韩一级电影网站 | 91精品国产乱码久久 | 99视频这里有精品 | 中文字幕乱码在线播放 | 99操视频| 99视频这里有精品 | 天天射天天射天天射 | av在线免费观看不卡 | 九九精品在线观看 | 国产精品不卡在线观看 | 国产二区视频在线 | 免费看一级特黄a大片 | 97电影在线| 欧美 日韩 视频 | 久久99九九99精品 | 国产小视频你懂的 | 日韩精品中文字幕在线 | 久草在线这里只有精品 | 在线天堂视频 | 天天干亚洲 | 麻豆视频免费在线 | 东方av在线免费观看 | 亚洲综合小说 | 日日干日日 | 久免费视频 | 免费看黄色大全 | 狠狠操狠狠插 | 日韩伦理一区二区三区av在线 | 四虎影视成人永久免费观看亚洲欧美 | 免费网站黄色 | 亚洲精品国 | 国产视频一区二区在线播放 | 免费看一级特黄a大片 | 91亚洲精品久久久蜜桃借种 | 国产美腿白丝袜足在线av | 在线欧美最极品的av | 欧美久久综合 | 人人爽人人舔 | 国产精品黄色影片导航在线观看 | 毛片二区 | 久久99视频精品 | 91av视频播放| 久久久久久久久久网 | 在线成人一区二区 | 欧美极品xxx| 久久色网站 | 久久成年人网站 | 日韩婷婷 | 久久精品专区 | 国产女人40精品一区毛片视频 | 一级大片在线观看 | 十八岁以下禁止观看的1000个网站 | 五月天久久久久 | 在线观看免费高清视频大全追剧 | 久久久久久久久久久免费视频 | 国产97在线观看 | 久久深夜福利免费观看 | 久久不射网站 | 97超碰人人澡人人爱学生 | 亚洲男人天堂a | 国产精品久久久久久五月尺 | 久久黄视频 | 极品嫩模被强到高潮呻吟91 | 日韩av片无码一区二区不卡电影 | 国产精品精品视频 | 欧美日韩国产亚洲乱码字幕 | 成人一区二区三区中文字幕 | 中文字幕av专区 | 久草久视频| 久久狠狠干 | 亚洲三级在线播放 | 99久久精品费精品 | 4438全国亚洲精品在线观看视频 | 奇米影视777影音先锋 | 午夜在线观看 | 久久久2o19精品 | 亚洲视频高清 | 国产精品成人免费精品自在线观看 | 欧美狠狠色 | 综合久色 | 国产精彩在线视频 | 亚洲精品美女视频 | 国产福利免费看 | 成人一区二区在线 | 国产视频精品在线 | 91粉色视频| 在线av资源 | 国产精品九九久久99视频 | 狠狠色综合网站久久久久久久 | 99精品热视频只有精品10 | 天天干天天射天天爽 | 日韩黄视频 | 人人看黄色 | 成人黄在线 | 色就是色综合 | 国产亚洲精品中文字幕 | 日韩av在线一区二区 | 中文字幕之中文字幕 | 日本久久久久久久久久久 | 欧美久久久一区二区三区 | 中文字幕91| 日韩欧美高清在线 | 国产网站av | 久久综合久久久久88 | 精品久久美女 | av再线观看 | 2022久久国产露脸精品国产 | 91免费在线视频 | 婷婷激情av | 久久草在线免费 | 日韩免费视频线观看 | 激情自拍av | 黄色三级在线观看 | 激情欧美一区二区三区免费看 | 五月婷婷在线视频观看 | 久久草精品 | 亚洲高清国产视频 | av免费看网站 | 久久久久久久久久久久99 | 国产精品乱码久久久 | 九九热国产 | 国产99爱 | 国产精品手机播放 | 最新高清无码专区 | 国产一区二区成人 | 精品国产欧美一区二区三区不卡 | 久久久国产一区二区 | 免费观看av网站 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 91丨九色丨蝌蚪丨老版 | 91资源在线播放 | 日韩美女免费线视频 | 亚洲精品永久免费视频 | 超碰999 | 亚洲欧美一区二区三区孕妇写真 | 96精品视频 | 日韩在线观看你懂的 | 麻豆视频免费入口 | 日韩中文字幕在线 | 亚洲人成网站精品片在线观看 | 在线精品亚洲一区二区 | 国产青春久久久国产毛片 | 色综合久久综合网 | 欧美一二三视频 | 国产一区在线不卡 | 国内一区二区视频 | 欧美日韩精品在线 | 欧美日韩高清一区二区 国产亚洲免费看 | 久久国产精品偷 | 97国产在线播放 | 久久在线精品 | 日韩三级视频 | 久久av免费 | 国产一区二区三区视频在线 | 日韩久久网站 | 91福利视频免费观看 | 亚欧日韩成人h片 | 五月在线视频 | 亚洲色图色 | 中文字幕在线看视频 | 国产成人精品综合久久久久99 | 麻豆免费在线视频 | 国产自产在线视频 | 欧美一级裸体视频 | 樱空桃av| 黄www在线观看 | 97成人精品视频在线观看 | 99热9 | 国产在线免费av | 精品亚洲视频在线 | 天天色天天射天天操 | 国产高清不卡在线 | 国产中文字幕网 | 国产伦精品一区二区三区… | 欧美性一级观看 | 996久久国产精品线观看 | 亚洲涩涩网 | 国产成人av电影在线观看 | 国产精品密入口果冻 | 久精品一区 | 成全免费观看视频 | 亚洲一区二区三区四区精品 | 看黄色91| 午夜久久久影院 | 国产在线精品二区 | 精品国产一区二区在线 | 久久人人爽人人爽人人 | 丁香五月亚洲综合在线 | 不卡av在线免费观看 | 香蕉视频一级 | 天堂av高清| 免费看成人av | 一级黄色毛片 | 首页av在线 | 在线视频免费观看 | 久久久国产精品免费 | 欧美一级视频一区 | 日韩午夜在线播放 | 在线免费中文字幕 | 久久国产精品免费视频 | 国产一区二区三区黄 | 精品一二 | 国产美女视频免费观看的网站 | 国产精品xxxx18a99 | 热久久免费视频精品 | 999视频网站 | 2019久久精品 | 日韩电影久久久 | 激情av资源网 | 国产黄色片在线 | 欧美日韩国产一区二区在线观看 | 在线视频麻豆 | 女人18精品一区二区三区 | 国产在线综合视频 | 91污在线观看 | 天天综合网久久 | 国产亚洲精品中文字幕 | av在线播放国产 | 亚洲综合黄色 | 亚a在线 | 成人羞羞免费 | 69亚洲精品| 久久经典国产视频 | 狠狠综合久久av | 香蕉影视 | 国产精品免费视频观看 | 男女拍拍免费视频 | 日韩一区二区三区免费电影 | 免费观看91视频大全 | 欧美一区二区日韩一区二区 | 国产精品一区二区麻豆 | 91插插插网站 | 国产女教师精品久久av | 久久久婷 | 亚洲成人免费观看 | 国产一二三精品 | 国产96在线观看 | 亚洲精品字幕 | 麻豆一区在线观看 | 性色av一区二区三区在线观看 | 亚洲视频99| 中文字幕在线有码 | 日韩av电影网站在线观看 | 天堂在线免费视频 | 日韩视频区 | 91福利小视频 | 在线91色 | 婷婷久久网站 | 91麻豆国产福利在线观看 | 欧美性大胆 | 欧美一级在线看 | 天天综合视频在线观看 | 亚洲精品视频免费在线观看 | 91精品在线播放 | 天天色天天干天天 | 狠狠狠狠狠狠干 | 国产精品视频在线观看 | 久久久精品视频网站 | 综合久久久 | 欧美日韩一区二区三区视频 | 91在线你懂的 | 亚洲一区二区三区在线看 | 中文字幕成人网 | 日韩精品偷拍 | 亚洲欧洲美洲av | 香蕉久久久久 | 亚洲91av| 国产视频2021| 国产成人亚洲在线电影 | 色网站免费在线观看 | 91在线看免费 | 在线91播放 | 成人午夜电影网 | 91片黄在线观 | 亚洲精品乱码久久久久久蜜桃91 | 91成人网页版 | 岛国精品一区二区 | www.天天射| 国产在线不卡精品 | 日韩中文在线电影 | 久久成人高清 | 亚洲精品乱码久久久久v最新版 | 久久久国产精品一区二区中文 | 久久综合狠狠综合久久激情 | 国产91aaa | 国产h在线观看 | 久久色网站 | 成人中文字幕av | 国产片免费在线观看视频 | 91看国产| 国产精品免费小视频 | 国产在线国产 | 在线免费视频一区 | 91.麻豆视频 | 日日夜夜av | 天天综合亚洲 | 国产分类视频 | 美女视频黄免费的 | 就色干综合 | 天天色天天操天天爽 | 最新中文字幕在线观看视频 | 欧美福利网站 | 97国产在线播放 | 国产免费不卡 | 国产日本高清 | av中文字幕剧情 | 成人免费视频在线观看 | 干狠狠| 人人搞人人爽 | 国产一级91 | 日韩在线色 | 色com网| 综合激情久久 | 国产高清在线永久 | 日韩91在线 | 亚洲国内精品 | 国产成人精品在线播放 | 欧美肥妇free| 久久免费美女视频 | 国产精品亚洲视频 | 亚州精品成人 | 成人午夜电影在线观看 | 国产永久免费高清在线观看视频 | 久久精品久久99精品久久 | 手机在线小视频 | 精品国产伦一区二区三区 | 午夜精品区 | 国产视频18 | 亚洲国产片色 | 日日夜日日干 | 国产亚洲婷婷免费 | 91成熟丰满女人少妇 | 国产免费高清视频 | 男女视频久久久 | 在线观看日韩精品 | 国产超碰在线观看 | 国产高清在线永久 | 午夜丁香视频在线观看 | 欧美在线91| 精品日韩中文字幕 | 精品国产伦一区二区三区观看方式 | 中文字幕在线观看视频网站 | 精品a在线 | 日日夜夜人人精品 | 91高清一区 | 色播99| 992tv人人网tv亚洲精品 | 免费在线观看日韩欧美 | 国产999精品久久久久久 | 97在线精品视频 | 99久久er热在这里只有精品15 | 一区二区三区四区精品视频 | 亚洲精品女人久久久 | 丁香综合激情 | 国产视频久| 欧美激情另类 | 日韩专区一区二区 | 国产色婷婷 | 中文字幕免费观看全部电影 | 久久黄色片 | 国产在线视频一区二区 | 亚洲高清激情 | 91在线公开视频 | av成人免费 | 精品在线免费观看 | 一区二区三区国 | 九九九九精品九九九九 | 99精品国产兔费观看久久99 | 久久超碰免费 | 亚洲影视九九影院在线观看 | 国产精品精品国产色婷婷 | 精品久久久久久亚洲综合网 | 国产福利av | 在线观看成人网 | 欧美福利片在线观看 | 天天玩天天干 | 免费看特级毛片 | 韩日av一区二区 | 麻豆免费观看视频 | 国产美女精品视频 | 日日干天天爽 | 91九色在线视频观看 | 91中文字幕在线观看 | 亚洲视频一级 | 手机在线看片日韩 | 日韩乱色精品一区二区 | 国产亚洲午夜高清国产拍精品 | 91成人欧美 | 免费看黄色小说的网站 | 又色又爽又黄高潮的免费视频 | 婷婷六月网 | 色大片免费看 | 天天综合天天综合 | ,午夜性刺激免费看视频 | 综合色狠狠| 久久色亚洲 | 天天干视频在线 | 婷婷六月天在线 | 丁香六月婷婷综合 | 亚洲在线视频观看 | 在线观看一区 | 玖玖在线观看视频 | 91丨九色丨勾搭 | 不卡av电影在线观看 | 狠狠色丁香婷婷综合橹88 | 91av视频 | 亚欧日韩av | 最新av在线播放 | 日韩免费一区二区三区 | 国产美女被啪进深处喷白浆视频 | 在线激情av电影 | 日韩欧美综合在线视频 | 色91av | 99视频精品全部免费 在线 | 在线观看免费国产小视频 | 激情网在线视频 | 蜜桃av久久久亚洲精品 | 国产精品黄| 国产精品一区二区免费在线观看 | 国产成人精品一区二区三区在线观看 | 国产 字幕 制服 中文 在线 | 中文字幕免费高清 | 成人av中文字幕在线观看 | a在线观看视频 | 日韩三级久久 | 欧美日韩一级久久久久久免费看 | 亚洲精品动漫成人3d无尽在线 | 国产精品免费观看视频 | 2019中文在线观看 | 一区二区影院 | 日韩久久激情 | 色综合天天综合在线视频 | 欧洲色吧 | 亚洲一二视频 | 中文字幕a∨在线乱码免费看 | 日韩三级av | 国产精品毛片久久久久久 | 中文视频一区二区 | av在线短片| 久久天天躁夜夜躁狠狠躁2022 | 黄色特一级片 | 91九色精品国产 | 深夜免费网站 | 久久久久激情视频 | 97视频精品| 天天摸天天弄 | 国产精品美女免费视频 | 国产乱视频 | 一区二区三区电影 | 久久黄色免费 | 天天干天天玩天天操 | 丁香色婷| 激情五月婷婷丁香 | 91精品999| 日韩av免费在线电影 | 国产精品麻豆三级一区视频 | 国产一级片一区二区三区 | 午夜视频在线观看网站 | 操操操夜夜操 | 国产一区在线观看视频 | 日本精品久久久久中文字幕5 | 91九色网站 | 久久在线免费视频 | 日韩视频在线一区 | 日韩在线观 | 国产美女在线观看 | 亚洲欧美日韩精品久久久 | av手机版 | 中文字幕乱码在线播放 | 91网站免费观看 | 欧美一区免费在线观看 | av在线免费播放网站 | 伊人久久在线观看 | 91夫妻视频 | 成人性生交大片免费看中文网站 | av成人在线播放 | 国产99久 | 久久精品99视频 | 激情丁香综合五月 | 黄p网站在线观看 | 色狠狠干 | 日日综合 | 久久好看| 日韩中文字幕视频在线 | 欧美精品xxx | 欧美日韩综合在线观看 | 色婷婷电影 | 91亚色视频在线观看 | 色婷婷免费视频 | 国产最新视频在线 | 久久精品2 | 国产亚洲精品久久19p | 一区二区三区视频在线 | 亚洲资源在线 | 狠狠干 狠狠操 | 91资源在线免费观看 | 久久精品中文字幕少妇 | 久久久久久高潮国产精品视 | 色视频网站在线 | 国产一区二区三区免费视频 | 色婷婷激情| 精品国产乱子伦一区二区 | 在线黄色国产电影 | 免费一级黄色 | 亚洲午夜久久久综合37日本 | 亚洲年轻女教师毛茸茸 | 亚洲精品乱码白浆高清久久久久久 | 久久久精品久久 | 99re在线视频观看 | 人人干人人搞 | 水蜜桃亚洲一二三四在线 | 久久久久色 | 啪啪动态视频 | 六月天色婷婷 | av线上看| 国产一区视频在线 | 亚洲韩国一区二区三区 | 国内精品久久久久久久久久久久 | 日韩在线高清视频 | 久久网站最新地址 | 日韩一级理论片 | av国产网站 | 天堂va在线观看 | 97国产人人 | 黄色a一级片 | 射射射综合网 | 中日韩男男gay无套 日韩精品一区二区三区高清免费 | 久久新| 久久国产精品一国产精品 | 国产无遮挡又黄又爽在线观看 | 日韩精选在线 | 亚洲第一中文字幕 | 久久久亚洲网站 | 日本在线观看黄色 | 成人久久网 | 国产免费黄色 | 中文字幕永久免费 | 国内视频一区二区 | 久久99久久精品国产 | 国产精品美女www爽爽爽视频 | 国产99久久久精品 | 亚洲资源网 | 人人爽人人澡人人添人人人人 | www一起操| 国产精品一区二区白浆 | 热久久免费视频 | 欧美日韩免费一区二区三区 | 久久综合九色 | 麻豆成人在线观看 | 中文字幕一区二区三区四区久久 | 免费a v观看 | 欧美大荫蒂xxx | 超碰精品在线观看 | 九九九九热精品免费视频点播观看 | 国产精品欧美 | 99综合影院在线 | www.午夜色.com | 久久综合九色综合久久久精品综合 | 免费在线视频一区二区 | 国产成人99av超碰超爽 | 国产一级片免费播放 | 精品专区一区二区 | 在线免费黄色片 | 欧美一区二区在线免费观看 | 99色99| 天天射,天天干 | 国产久视频 | 欧美综合久久 | 久久久久免费精品国产小说色大师 | 日韩av免费一区 | 精品a视频 | 精品久久久久久国产 | 中文字幕在线播放一区 | 人人看人人艹 | 天天爱综合 | 91 中文字幕 | 国产精品九九九九九 | 日韩在线观看视频免费 | a久久久久 | 国产亚洲欧洲 | 国产亚洲精品久久久久久网站 | 日韩高清一二区 | 成人av手机在线 | 亚洲日本在线视频观看 | 中文视频在线看 | www.五月天婷婷.com | 欧美一级免费高清 | 久久精品国产免费 | 2018好看的中文在线观看 | 日韩三级视频在线观看 | 久久国产精品精品国产色婷婷 | 99久高清在线观看视频99精品热在线观看视频 | 国产精品99久久久久久武松影视 | 天天爱天天舔 | 在线免费观看av网站 | 六月丁香色婷婷 | 日韩成人av在线 | 亚洲精品国偷自产在线91正片 | 99国产一区二区三精品乱码 | 天天做夜夜做 | 91看片麻豆 | 成人97视频一区二区 | 日韩在线一区二区免费 | 日本中文字幕久久 | 亚洲va综合va国产va中文 | www.狠狠 | 日韩天天综合 | 久久99久久精品 | 国产精品一区二区三区在线播放 | 中文一区在线观看 | 成人三级黄色 | 99精品国产高清在线观看 | 九九99| 欧美色综合天天久久综合精品 | 最近中文字幕高清字幕免费mv | 国产日韩在线看 | 亚洲色图22p | 一区二区久久 | 91成年人在线观看 | 国产福利不卡视频 | 国内精品久久久久影院男同志 | 黄色国产在线观看 | 国产精品你懂的在线观看 | 色偷偷888欧美精品久久久 | 97在线观看免费高清完整版在线观看 | 国产一区二区精品久久91 | 91c网站色版视频 | 国产福利一区在线观看 | 国产特级毛片aaaaaa毛片 | 国产一区二区在线免费播放 | 天天操天天舔天天爽 |