優化Oracle資料庫查詢10個方法
但是,當用戶在一張大表中採用這個LIKE語句的話,就會發現這個查詢語句的執行效率非常的慢。這是什麼原因造成的呢?其實,不管是Like 關鍵字,若採用MATCHES關鍵字的話,若在大量資料中查詢符合條件的記錄,則其執行效率也比較低。這主要是其技術特性所造成的。
Like與Matches兩個關鍵字,其支援萬用字元匹配。在有些專業書籍上把這個叫做“正規表示式”。不過由於在利用這些關鍵字查詢的時候, 資料庫系統不是通過索引來查詢,而是採用順序掃描的方式來查詢。顯然,真是這種技術特性,造成了Like與Mateches兩個關鍵字查詢效率的低下。特別是在複雜查詢或者大表查詢中,使用者可以明顯感覺到速度比較慢。
索引是資料庫中的一個重要的資料結構。索引如果利用的合理的話,可以大幅度的提升資料庫的查詢效能。一般情況下,我們在資料庫設計的時候,要充分的利用索引,來提高資料庫的執行效率。如對於一些經常需要用到的查詢功能,我們需要為沒有指定外來鍵的列建立索引;如有查詢大表資料,而且又需根據好幾個欄位的值對其進行排序,也需要在這些列上建立複合索引。特別是在一些應用系統上,往往可以按以下欄位的名稱,就會對這個欄位進行排序。遇到這種情況的話,更加需要在這些頻繁進行排序的列上建立索引,以提高重新排序的效率。可見,若在查詢的時候,若不能利用索引提高查詢效率的話,則就好像跑車失去四輪驅動,速度會大受影響。
所以,在資料庫系統設計中,要儘量避免採用Like或者Matche關鍵字。有時候,我們可以利用其他運算子號來代替。如我們可以利用〉(大於)或者<(小於)符號來達到類似的需求。若真的要採用這兩個關鍵字的話,則就需要做好查詢優化方面的工作。如不要在基礎表中直接利用這個兩個關鍵字,而是通過報表檢視、或者臨時表等來查詢,以減少其不良影響。
第九個方法
在資料庫設計中,有一個非常奇怪的現象。一些專家級的資料庫設計人員,在寫查詢語句的時候,非對語句進行詳細的註釋。有時會,註釋的內容大大超過了查詢程式碼本身的篇幅。可是,往往一些入門不久的資料庫設計人員,不喜歡寫註釋語句。這是一個很反常的現象。
筆者剛開始接觸資料庫的時候,也不喜歡寫註釋語句。覺得寫註釋語句太浪費時間。但是,一個偶然的事件讓筆者改掉了這個壞習慣。那時筆者在觀摩一個專家設計資料庫的時候,被其密密麻麻的註釋驚呆了。看了其程式碼之後,筆者可以非常輕鬆的閱讀完其所有的程式碼。不愧為是專家級的人物。看了他的註釋之後,在看看自己編寫的程式碼注視,那真是大巫見小巫了。從此之後,筆者也在慢慢培養自己編寫程式碼的習慣。現在筆者在資料庫設計的時候,註釋已經寫的很詳細了。至少筆者的同事在看到我的註釋之後,不用看原始碼就知道筆者要實現的目的了。
在編寫註釋的時候,要注意幾個問題。
一是註釋越詳細越好。其實,註釋最多犧牲一點磁碟空間,而不會對資料庫的效能產生任何不良的影響。相反,註釋詳細的話,對於後續資料庫維護與管理、系統二次開發的等等,都會提供很大的幫助。
二是最好採用英文註釋。若採用中文註釋的話,有時候資料庫語言設定不當,在資料庫例項安裝的時候,不會把中文的註釋帶過去。所以,作為資料庫管理員,要有一定的英語基礎,學會利用英語寫註釋。其實,這也不是很難。只要多看看別人設計的資料庫註釋,把他們常用的註釋複製下來。通過選擇合適的進行復制、貼上就可以完成任務。
三是不僅在寫查詢語句的時候,要做好程式碼的註釋工作。在編寫其他程式碼的時候,如過程、函式等等,也要新增詳細的程式碼。以增加這些複雜功能的可讀性。
四是註釋的內容。一般註釋應該包含如下幾方面的內容。一是這段程式碼要實現的功能;二是這段程式碼需要呼叫的引數;三是這段程式碼輸出的結果。若是多表關聯查詢的話,最好能夠說明表之間的對應關係。若在查詢語句中,直接呼叫了函式的話,則最好能夠註明這個函式的功能;等等。終止一個原則就是,讓其他人看到這個註釋,不再需要去查詢其他的資料,就可以明白這段程式碼的含義。
詳細的註釋內容,不僅不會降低資料庫的執行效能,而且還可以提高資料庫的管理與維護的效率;同時也可以加快前臺應用程式開發設計的速度。又因為查詢語句是系統中利用的最多的語句,也是引用的最頻繁的語句。故在查詢語句中,更加需要做好相關的註釋。
第十個方法
在使用一些大型管理系統的時候,如ERP系統。我們若查詢產品資訊,預設的情況下,若記錄比較多的時候,其不會把所有的記錄都查詢出來。如在ERP系統的資料庫中,其有20000個產品資訊。而端子類的產品資訊就佔據到1000個。此時,我們在查詢條件中,若產品類別限制為“端子”的話,則其查詢出來的結果也可能不是所有的端子。預設顯示的話,可能只有前面的100個端子類產品。若使用者需要看到全部的產品資訊,就需要點選“顯示全部”按鈕,才可以顯示出全部的資訊。
其實,不管是一些應用程式如此設計,在Oracle資料庫中,本身也有這方面的限制。如直接在PL/SQL客戶端中查詢資料的話,其顯示的記錄預設情況下也是有限制的,而不會把所有符合條件的語句查詢出來。若使用者需要查詢所有符合條件的記錄,則需要點選“繼續”按鈕,以讓資料庫顯示所有的記錄。
為什麼要做類似的限制呢?這主要就是為了提高資料庫查詢的效能。我們直接在資料庫伺服器上,在幾百萬條記錄中查詢的話,顯示幾百條記錄跟現實幾千條記錄所花費的時間明顯不同。前者可能只需要3秒即可。而後者可能需要1分鐘。所以,為了減少使用者等待的時間,我們往往需要限制首次查詢預設顯示的記錄數字。
如我們往往在查詢語句中,利用top 100 來讓資料庫只顯示前100條記錄。如此的話,可以明顯的縮短使用者的等待時間。預設情況下,是根據記錄建立的時間順序,來顯示記錄的。最遲建立的記錄,其顯示在最前。以此類推。
當用戶需要的資料在前面100條之內,則就不需要再檢視其他記錄了。相反,若不在的話,則就需要查詢全部記錄資訊了。
一是要靈活放置COUNT函式的位置,因為利用COUNT函式統計記錄數的時候,是會考慮空行的記錄的。如在資料表中一般有序列欄位與其它的有意義欄位兩類。有時候可能序列欄位中有內容而其它欄位中沒有內容,則在利用COUNT函式統計記錄數量的時候,會把這個空記錄也考慮進去。很明顯,則就會發生統計的錯誤。所以,這個COUNT函式該放在哪個位置上,還是比較講究的。一般的話,筆者試建議不要放在序列號欄位上,而要放在一些關鍵的實體欄位中。如統計員工人數的時候,則就可以放在員工姓名或者編號上等等。
二是靈活跟其它函式搭配使用。如在上面的例子中,筆者談到有時候使用者需要知道現在有員工編制的部門與職位有哪一些,我們可以利用DISTINCT函式來找出具體的部門。但是,我現在只想知道有編制的部門與職位具體有多少,此時,我們也可以利用COUNT 與DISTINCT函式結合應用,找出我們所需要的資料。在COUNT函式中,可以指定ALL與DISTINCT選項。預設的情況下,是ALL選項,表示統計所有的行,其中也包括重複的行。而DISTINCT就表示只統計不重複的行。可見,COUNT函式跟其它函式搭配使用的話,可以簡化我們的查詢語句,提高查詢效率。
第五個方法:只查詢時必須的欄位。
有時候,使用者不同的查詢需求都要用到同一張表。如在員工資訊表中包含了很多內容。有時候使用者想要知道正式員工有多少;管理層員工有多少;生產線員工又有哪些;或者想知道合同即將到期的員工有哪些。為此,就遇到一個問題,因為這些內容基本上都是在同一張表中,那是在同一個檢視中實現,而是根據需求不同,設計不同的檢視呢?
若單從技術上考慮,兩這都是可以實現的,不會有多大的難度。但是,若是從資料庫效能上考慮在,則還是採用不同的檢視來實現不同的需求為好。
一方面,若從安全方面講,則可以根據不同的檢視來控制相關的訪問許可權。可見,把檢視細化,在許可權控制上則會更加的靈活。
另一方面,資料的查詢效率,跟資料內容的多少也有非常密切的關係。如在查詢員工合同到期資訊的時候,一般不需要員工的地址資訊等等。若把這個資訊也查詢出來的話,由於這個欄位比較長,就會花費比較長的時間。所以,在資料庫設計中,我們要學會根據使用者不同的需求,設計不同的檢視。雖然可能這在設計的時候會比較花時間,但是,在確可以提高資料庫的效能與安全性。這筆生意還是划得來的。
第六個方法:合理處理NULL欄位。
Null欄位在資料庫中是一個比較特殊的欄位。Null欄位表示未知值或者說缺少資料,注意若某個欄位的值為Null,則這個欄位即不是空格,也不是0。當插入記錄的時候,若這個欄位沒有被賦值,而且也沒有預設值的話,則這個欄位系統預設給他的值就是“Null”。
由於這個值比較特殊,在查詢的時候,及時經驗豐富的資料庫管理員,有時候在處理起來的時候,也會發生錯誤。為此,筆者在這裡總結一些,在資料庫查詢的時候,關於這個空欄位查詢的一些需要注意的地方。
一是要注意NULL欄位的數字運算問題。
如現在在一個薪資管理系統中,有一張薪資表,其中有基本工資與加班工資兩個欄位。若某個使用者的基本工資為2000,而其加班工資沒有。在輸入這條記錄的時候,由於加班工資這個欄位中,沒有輸入資料,而且在資料庫設計的時候,也沒有個這個欄位設定0的預設值。所以,當這條記錄儲存的時候,資料庫系統會給這個欄位自動賦值,這個欄位的值就為NULL。
若我們用Select語句查詢這條記錄的時候,其加班工資這個欄位顯示的資料是空的。看起來好像是空格,而實際上其儲存的不是空格。此時,我們若利用查詢語句想知道,這個員工的總的工資(即加班工資加上基本工資)為多少的時候會有什麼結果呢?
我們可以利用Select 員工姓名,基本工資,加班工資,基本工資+加班工資 as 總工資 FROM 員工薪資表; 我們可以通過這條語句來查詢這個員工總的工資是多少。但是,這條語句會查詢出我們想要的結果嗎?我們執行一下這條語句,結果我們會發現,得出的結果跟我們想象的大相徑庭。最後顯示的總工資一欄中,為空格。
原來,Oracle資料庫設計中,若一個NULL欄位跟其他欄位進行四則運算時,其顯示的結果都為空。所以,若一個欄位為NUU,則無論加減乘除,最後其結果都返回的施NULL值。這顯然跟我們想象的不同。
針對這種情況,我們該如何處理呢?在資料庫設計過程中,主要有兩種處理方法。 一是在設計表的時候,對於這些需要參與運算的欄位,要設定預設值。如可以把這個欄位的預設值設定為0。則當新增這條記錄的時候,即使前臺使用者沒有給其設定值。在儲存資料的時候,系統也會給其預設值0。如此的話,在進行四則運算的時候,才可能得到我們想要的值。 二是在查詢的時候,需要考慮到這個NULL值的影響。有時候,若資料庫中已經有記錄,則不能夠改變資料庫欄位的預設值。遇到這種情況,若我們需要對NULL欄位與數字欄位進行四則運算的時候,又該如何處理呢?此時,我們就需要在查詢的時候,給NULL欄位賦0的值。具體我們可以在查詢語句中,如此定義。Select 員工姓名,基本工資,加班工資,基本工資+NVL(加班工資,0) as 總工資 FROM 員工薪資表;如此的話,當加班工資的值為NULL的時候,則系統在運算的時候,會把其當作0來處理。這麼處理,我們就可以得到我們所想要的結果。不過一般情況下,這一種處理方式是不得已而為之的。最好的是,在資料庫表設計的時候,就給相關的欄位設定0的預設值。 另外,還有一個函式NVL2跟NVL函式功能類似,只是其多了一個引數而已,其表示式為NVL2(引數1,引數2,引數3)。它的含義是,當引數1不為空值時,則返回的值為引數2;當引數1是空值時,則範圍的是引數3。若用這個函式實現NVL函式的目的時,則就需要如此改寫上面這個案例的函式引數寫法:NAV2 (加班工資,基本工資+加班工資,基本工資)。可見,兩個函式有異曲同工之妙。具體採用哪種函式為好,則就需要根據資料庫管理員的愛好來選擇了。 二是如何查詢NULL欄位。 如果現在有一張員工基本資訊表,其中有一個身份證號碼的欄位。現在若使用者想知道,有哪些員工還沒有記錄身份證號碼資訊,該如何做呢?由於這個NULL欄位不為空格或者0。若我們在查詢條件語句中,利用’0’ 或者’’(空格)作為查詢條件的話,是查不到我們所需要的結果的。此時,在資料庫中,提供了一個專門使用者查詢NULL欄位記錄的函式IS NULL。若我們現在想知道哪些員工沒有註明身份證資訊時,就可以利用如下的語句來實現。 Select 員工姓名,身份證號碼 from 員工基本資訊表 where 身份證號碼 is not null; 通過以上這條語句就可以實現查詢身份證件為空的員工資訊的目的。 第七個方法:多多利用模糊查詢。 在應用系統設計的時候,若讓使用者完整的輸入全部查詢條件,這個要求對於普通使用者來說,過於苛刻。做過軟體專案培訓或者實施的時候,出於種種原因,使用者在查詢的時候,往往只輸入部分的輸入條件。遇到這種情況的時候,就需要在查詢設計的時候,實現模糊查詢。如此的話,即使使用者輸入的查詢條件不全,也可以查詢出相關的內容。 如使用者在查詢某個產品資訊的時候,其可能不記得某個產品的具體名稱,只知道其叫做端子,而其他具體的資訊不清楚。此時,只需要在名稱欄位或者規格欄位處輸入端子,就可以從系統中查詢中這兩個欄位中含有“端子”的紀錄資訊。如此的話,使用者只需要在查詢出的結果中繼續查詢即可。 這就告誡我們資料庫管理人員,在資料庫系統設計的時候,需要多用用模糊查詢的功能。 具體的來說,需要注意以下幾方面內容。 一是大小寫不要進行區分。預設情況下,在資料庫查詢的時候,大小寫是區分的。也就是說,現在有個欄位內容為ABC,則我們查詢abc的時候,就查不到這條記錄。因為其大小寫不同。而作為前段應用程式的使用者來說,往往其在輸入查詢條件的時候,其並不會區分英文的大小寫。雖然,不區分大小寫也可以在前端應用程式中實現,不過,一般來說,在資料庫中實現要比在前端系統中實現簡單的多。故筆者是建議在後臺數據庫中實現這個大小寫的自動轉換功能。在查詢的時候,不要區分大小寫。這可能就是國內的特有國情吧。 二是要實現前後模糊查詢。如現在有個欄位的內容為“好好學習”,若我現在輸入查詢條件為學習、好好、好學等,都可以查到這條件記錄。此時該如何設計查詢的條件語句呢?這就是前後模糊查詢的概念。其實,要實現這個功能也很簡單。在前臺查詢語句設計的時候,當把查詢條件傳遞給後臺資料庫系統的時候,在查詢引數的前後,分別加入模糊查詢的引數%即可。即我們若輸入的查詢條件語句為“好學”,則其傳遞給資料庫的引數為“%好學%”。如此,就可以實現我們所需要的模糊查詢。一般來說,模糊查詢需要前臺應用程式與後臺資料庫之間共同實現,這麼處理起來,工作量會少許多;也會提高資料庫的執行效率。 三是通過Beteen函式實現模糊查詢。如現在有一個考勤系統,某個員工想知道自己在9月份自己的加班情況時,只需要在查詢條件中,輸入時間為9月1日到9月30日時,就可以查詢到自己所需要的資訊。這就是通過Beteen函式來實現模糊查詢的。筆者以前碰到過一個平臺型的ERP系統,他在這方面作的不錯。這個產品就可以自己設計相關的報表。在報表設計中,在基於日期的查詢條件,其即可以查詢單個日期,而且還可以查詢某個範圍內的紀錄。這就使利用了這個函式。另外,可以實現模糊查詢的函式還有IN函式等等。作為資料庫管理人員,需要從提高資料庫的查詢效能角度出發,合理選擇這些模糊查詢函式。並且,還需要配合前臺應用程式設計,處理好模糊查詢的功能。 第八個方法:慎用Like等萬用字元。 Like關鍵字,從技術上來說,是一個非常友善的萬用字元。利用這個萬用字元,我們可以實現很多模糊查詢。如現在在一個人事檔案系統中,使用者想知道身份證號碼以“339005”開頭的人事資訊,此時,就可以利用Like語句實現。我們可以利用下面的條件語句,實現我們的需求,“where 身份證號碼 like ‘339005%’”。通過這個條件語句,可以查到所有身份證以339005開頭的號碼。 但是,當用戶在一張大表中採用這個LIKE語句的話,就會發現這個查詢語句的執行效率非常的慢。這是什麼原因造成的呢?其實,不管是Like 關鍵字,若採用MATCHES關鍵字的話,若在大量資料中查詢符合條件的記錄,則其執行效率也比較低。這主要是其技術特性所造成的。 Like與Matches兩個關鍵字,其支援萬用字元匹配。在有些專業書籍上把這個叫做“正規表示式”。不過由於在利用這些關鍵字查詢的時候, 資料庫系統不是通過索引來查詢,而是採用順序掃描的方式來查詢。顯然,真是這種技術特性,造成了Like與Mateches兩個關鍵字查詢效率的低下。特別是在複雜查詢或者大表查詢中,使用者可以明顯感覺到速度比較慢。 索引是資料庫中的一個重要的資料結構。索引如果利用的合理的話,可以大幅度的提升資料庫的查詢效能。一般情況下,我們在資料庫設計的時候,要充分的利用索引,來提高資料庫的執行效率。如對於一些經常需要用到的查詢功能,我們需要為沒有指定外來鍵的列建立索引;如有查詢大表資料,而且又需根據好幾個欄位的值對其進行排序,也需要在這些列上建立複合索引。特別是在一些應用系統上,往往可以按以下欄位的名稱,就會對這個欄位進行排序。遇到這種情況的話,更加需要在這些頻繁進行排序的列上建立索引,以提高重新排序的效率。可見,若在查詢的時候,若不能利用索引提高查詢效率的話,則就好像跑車失去四輪驅動,速度會大受影響。 所以,在資料庫系統設計中,要儘量避免採用Like或者Matche關鍵字。有時候,我們可以利用其他運算子號來代替。如我們可以利用〉(大於)或者<(小於)符號來達到類似的需求。若真的要採用這兩個關鍵字的話,則就需要做好查詢優化方面的工作。如不要在基礎表中直接利用這個兩個關鍵字,而是通過報表檢視、或者臨時表等來查詢,以減少其不良影響。 第九個方法:利用註釋提高查詢語句的可讀性。 在資料庫設計中,有一個非常奇怪的現象。一些專家級的資料庫設計人員,在寫查詢語句的時候,非對語句進行詳細的註釋。有時會,註釋的內容大大超過了查詢程式碼本身的篇幅。可是,往往一些入門不久的資料庫設計人員,不喜歡寫註釋語句。這是一個很反常的現象。 筆者剛開始接觸資料庫的時候,也不喜歡寫註釋語句。覺得寫註釋語句太浪費時間。但是,一個偶然的事件讓筆者改掉了這個壞習慣。那時筆者在觀摩一個專家設計資料庫的時候,被其密密麻麻的註釋驚呆了。看了其程式碼之後,筆者可以非常輕鬆的閱讀完其所有的程式碼。不愧為是專家級的人物。看了他的註釋之後,在看看自己編寫的程式碼注視,那真是大巫見小巫了。從此之後,筆者也在慢慢培養自己編寫程式碼的習慣。現在筆者在資料庫設計的時候,註釋已經寫的很詳細了。至少筆者的同事在看到我的註釋之後,不用看原始碼就知道筆者要實現的目的了。 在編寫註釋的時候,要注意幾個問題。 一是註釋越詳細越好。其實,註釋最多犧牲一點磁碟空間,而不會對資料庫的效能產生任何不良的影響。相反,註釋詳細的話,對於後續資料庫維護與管理、系統二次開發的等等,都會提供很大的幫助。 二是最好採用英文註釋。若採用中文註釋的話,有時候資料庫語言設定不當,在資料庫例項安裝的時候,不會把中文的註釋帶過去。所以,作為資料庫管理員,要有一定的英語基礎,學會利用英語寫註釋。其實,這也不是很難。只要多看看別人設計的資料庫註釋,把他們常用的註釋複製下來。通過選擇合適的進行復制、貼上就可以完成任務。 三是不僅在寫查詢語句的時候,要做好程式碼的註釋工作。在編寫其他程式碼的時候,如過程、函式等等,也要新增詳細的程式碼。以增加這些複雜功能的可讀性。 四是註釋的內容。一般註釋應該包含如下幾方面的內容。一是這段程式碼要實現的功能;二是這段程式碼需要呼叫的引數;三是這段程式碼輸出的結果。若是多表關聯查詢的話,最好能夠說明表之間的對應關係。若在查詢語句中,直接呼叫了函式的話,則最好能夠註明這個函式的功能;等等。終止一個原則就是,讓其他人看到這個註釋,不再需要去查詢其他的資料,就可以明白這段程式碼的含義。 詳細的註釋內容,不僅不會降低資料庫的執行效能,而且還可以提高資料庫的管理與維護的效率;同時也可以加快前臺應用程式開發設計的速度。又因為查詢語句是系統中利用的最多的語句,也是引用的最頻繁的語句。故在查詢語句中,更加需要做好相關的註釋。 第十個方法:必要的時候,限制使用者所使用的行。 在使用一些大型管理系統的時候,如ERP系統。我們若查詢產品資訊,預設的情況下,若記錄比較多的時候,其不會把所有的記錄都查詢出來。如在ERP系統的資料庫中,其有20000個產品資訊。而端子類的產品資訊就佔據到1000個。此時,我們在查詢條件中,若產品類別限制為“端子”的話,則其查詢出來的結果也可能不是所有的端子。預設顯示的話,可能只有前面的100個端子類產品。若使用者需要看到全部的產品資訊,就需要點選“顯示全部”按鈕,才可以顯示出全部的資訊。 其實,不管是一些應用程式如此設計,在Oracle資料庫中,本身也有這方面的限制。如直接在PL/SQL客戶端中查詢資料的話,其顯示的記錄預設情況下也是有限制的,而不會把所有符合條件的語句查詢出來。若使用者需要查詢所有符合條件的記錄,則需要點選“繼續”按鈕,以讓資料庫顯示所有的記錄。 為什麼要做類似的限制呢?這主要就是為了提高資料庫查詢的效能。我們直接在資料庫伺服器上,在幾百萬條記錄中查詢的話,顯示幾百條記錄跟現實幾千條記錄所花費的時間明顯不同。前者可能只需要3秒即可。而後者可能需要1分鐘。所以,為了減少使用者等待的時間,我們往往需要限制首次查詢預設顯示的記錄數字。 如我們往往在查詢語句中,利用top 100 來讓資料庫只顯示前100條記錄。如此的話,可以明顯的縮短使用者的等待時間。預設情況下,是根據記錄建立的時間順序,來顯示記錄的。最遲建立的記錄,其顯示在最前。以此類推。 當用戶需要的資料在前面100條之內,則就不需要再檢視其他記錄了。相反,若不在的話,則就需要查詢全部記錄資訊了。 |