SQL查詢語句性能優化建議
1、查列表時,盡量把要查的字段查出,select id,name from 這樣比select * from 效率高點。
2、一個頁面有很多List要查,而這些List又屬于同一個表,只是條件不同,可以用or將所有的條件放在一個語句中,查出List,再用if根據條件判斷封裝不同List,這將很多個數據庫鏈接轉化成了一個數據庫鏈接,hibernate只要創建一個sessionfactory,效率比同時查多個語句快。
3、盡量把需要的字段放在同一張表上,這和第二條類似。
【查詢優化】怎樣用SQL語句查看查詢的性能指標
捍郵?莼撼逯卸寥〉氖?菀呈? 物理讀取:從物理磁盤中往緩沖讀取的數據頁數; 預讀:根據執行計劃從物理磁盤中往緩沖讀取的數據頁數; 其中對于首次查詢一般情況下會有一下關系:邏輯讀取=物理讀取+預讀(其中的具體聯系,由于已經在之前的博客文章中提到,就不再詳細說明(文章名為【查詢優化】MSSQL查詢執行流程)) 同理,后面的lob邏輯讀取、物理讀取、預讀概念理解差不多,只是是對相應表進行更新或插入操作時體現。 對于掃描計數,以上圖片的查詢沒有連接查詢,因此意義不大。不過,如果連接查詢來說,特別是循環查詢那種,比如說自連接,如果循環次數越多,則掃描次數也就越多,則會使得查詢的效率越低。這是掃描計數是一個比較重要的性能體現參數。 對于邏輯讀取,由于SQLSERVER中對數據進行任何操作都要把數據讀入到緩沖當中,如果邏輯讀取的頁數越多,則查詢的性能越低。為此,邏輯讀取一般都是查詢性能體現的一個重要參數。二、SET STATISTICS TIME (SQL Server解析和編譯時間) 上面顯示的信息表明,執行這次查詢使用了多少CPU運行時間和運行查詢使用了多少時間。CPU運行時間是對運行查詢所需要的CPU資源的一種相對穩定的測量方法,與CPU的忙閑程度沒有關系。但是,每次運行查詢時這一數字也會有所不同,只是變化的范圍沒有總時間變化大。總時間是對查詢執行所需要的時間(不計算阻塞或讀數據的時間),由于服務器上的負載是在不斷變化的,因此這一數據的變化范圍有時會相當地大。
總的來說,量化地來看一個查詢語句的性能可以在幾個參數進行比較:1、CPU時間。可以比較查詢的循環掃描次數和邏輯讀取的數據量;
優化sql 語句的幾種方式
1.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
2.應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num is null 可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:select id from t where num=03.應盡量避免在 where 子句中使用!=或操作符,否則將引擎放棄使用索引而進行全表掃描。4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num=10 or num=20 可以這樣查詢:select id from t where num=10 union all select id from t where num=* 和 not in 也要慎用,否則會導致全表掃描,如:select id from t where num in(1,2,3) 對于連續的數值,能用 between 就不要用 in 了:select id from t where num between 1 and 36.下面的查詢也將導致全表掃描:select id from t where name like '%abc%'7.應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。
如:select id from t where num/2=100 應改為:select id from t where num=100*28.應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:select id from t where substring(name,1,3)='abc'--name以abc開頭的id 應改為:select id from t where name like 'abc%'9.不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
10.在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用,并且應盡可能的讓字段順序與索引順序相一致。11.不要寫一些沒有意義的查詢,如需要生成一個空表結構:select col1,col2 into #t from t where 1=0 這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:create table #t(。
)12.很多時候用 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=*)13.并不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用。14.索引并不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。15.盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。
這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。16.盡可能的使用 varchar 代替 char ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
17.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。18.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
19.臨時表并不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對于一次性事件,最好使用導出表。
20.在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。21.如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統表的較長時間鎖定。
22.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該考慮改寫。23.使用基于游標的方法或臨時表方法之前,應先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。
24.與臨時表一樣,游標并不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。
在結果集中包括“合計”的例程通常要比使用游標執行的速度快。如果開發時間允許,基于游標的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
25.盡量避免大事務操作,提高系統并發能力。26.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
如何優化SQL語句中的物理查詢
from tab1, tab2 where tab1。
id = tab2。id and tab1。
col1 = 123 and tab2。col1 = 'abc' 照你所述的執行順序,先要tab1和tab2進行笛卡爾乘積,再按照tab1。
col1 = 123 and tab2。col1 = 'abc'進行篩選。
這樣的話,效率豈不是很低,數據庫有這么愚蠢嗎? 我想很多人都會有這個疑問,包括我在最初學習的時候也提出過這樣的問題。那么,我的這篇文章就結合這個問題來討論一下SQL Server的物理查詢處理。
首先我們必須明白邏輯處理和物理處理和區別,邏輯處理是指執行一個查詢應該產生什么樣的結果,那么邏輯查詢的各個階段就是這個查詢從邏輯上執行的先后順序,依照這個先后順序就能得到正確的結果,正如我們做四則混合運算一樣,先乘除后加減才能得到正確結果。 所以說邏輯查詢只關心產生一個我們期望的、正確的結果,它并不關心產生這個結果需要多少的資源消耗。
而物理處理就是怎么得到這個結果,這個時候才會考慮性能問題。下面我們就討論下怎么執行這個物理處理的。
當一個查詢到達數據庫引擎的時候,數據庫引擎需要做的是執行這個查詢的查詢計劃,那么這個時候就存在兩種情況,一種可能是這個查詢的查詢計劃已經在緩存中,這種情況就直接執行這個查詢計劃。 另外一種情況就是在緩存中找不到該查詢的查詢計劃。
沒有怎么辦?生成一個!怎么生成? 執行計劃是在編譯階段生成的,編譯需要經過三個步驟:分析、代數化(algebrization)、查詢優化,看見沒有這里的查詢優化過程就能解決上面的朋友提出的先笛卡爾集在篩選造成性能低的問題。 下面我就對這三個步驟作一個介紹。
第一步:分析是檢查語法并把SQL批處理轉化成分析樹的過程,如select * t1 where id in(1,2,3,4,5,6,7)在被分析樹分析后就展開成了select * t1 where id=1 or id=2 or id=3 or id=4 or id=5 or id=6 or id=7 ,除此之外還有檢查語法是否正確的功能。 第二步:接下的過程是代數化(algebrization),這個階段使用SQL Server 2005的新組件algebrizer,algebrizer組件的主要功能是綁定,因此代數化過程通常稱為綁定。
這個階段是將第一步的分析樹作為輸入,生成被稱為查詢處理器樹的輸出,用于查詢優化。 其實這個階段主要做幾個事情, 一:運算符平展,簡單的講就是把二元運算符組合成N元運算符,這里必須給出一個示例才能很好的解釋這個二元轉換成N元如第一步所示in操作展開成了一連串的or運算符,而分析器認為這些or都是二元的,也就是說它認為第一個or 的左孩子是id=1,右孩子是 (id=2 or id=3 or id=4 or id=5 or id=6 or id=7 )這個表達式,而右孩子又被認為是二元的,如此一來就必須進行一個遞歸過程。
而運算符平展過程則將這種二元運算組合成n元運算符,就避免了遞歸的過程。 二:名稱解析,這個過程其實就是檢查這個查詢中出現的表或者是表的列是不是在數據庫中真實存在。
以及在該查詢過程中是不是可見的。三:類型派生,有點抽象,舉個例子就能理解了,比如union查詢吧,union左右兩邊查詢結果對應位置的數據類型應該是一致的。
四:聚合綁定和組分綁定,執行完這個步驟后查詢處理器樹便生成了。 第三步:查詢優化,這個過程由查詢優化器組件來完成的。
查詢中應該以何種順序訪問表,使用哪種方法和使用哪個索引,應該由哪個聯接算法等都是由查詢優化器組件來決定的,但是這個決定也不是隨意的,它必須滿足的前提條件是保證最后得到的結果集必須是正確的,也就是說該結果集必須遵循邏輯處理的各個階段所得到的結果集相同。 優化器會嘗試該查詢的許多變體,一查找成本最低的計劃。
如果優化器分析該查詢的元數據得知只有一個可執行的計劃,那么它就不會再嘗試尋求更好的計劃,這個步驟叫做細微計劃優化。 如果沒有找到細微計劃優化,SQL Server將執行一些簡化,簡化就是對自身語法作一些轉換,比如在聯接前計算表的where篩選器,如前一篇描述的,邏輯查詢中where篩選總是在聯接之后計算,但是先計算where篩選器在聯接同樣能得到的正確的結果,而這樣的效率往往是更高的,所以在物理處理中where往往在join前執行的,開篇提到的那個問題只是讀者未理解邏輯處理和物理處理的差別而已。
什么是SQL的查詢優化,舉例說明
1 使用SET NOCOUNT ON 選項: 缺省地,每次執行SQL語句時,一個消息會從服務端發給客戶端以顯示SQL語句影響的行數。
這些信息對客戶端來說很少有用。通過關閉這個缺省值,你能減少在服務端和客戶端的網絡流量,幫助全面提升服務器和應用程序的性能。
為了關閉存儲過程級的這個特點,在每個存儲過程的開頭 包含“SET NOCOUNT ON”語句。 2 正確使用UNION和UNION ALL: 許多人沒完全理解UNION和UNION SELECT是怎樣工作的,因此,結果浪費了大量不必要的SQLServer資源。
當使用UNION時,它相當于在結果集上執行SELECT DISTINCT。換句話說,UNION將聯合兩個相類似的記錄集,然后搜索重復的記錄并排除。
如果這是你的目的,那么使用UNION是正 確的。但如果你使用UNION聯合的兩個記錄集沒有重復記錄,那么使用UNION會浪費資源,因為它要尋找重復記錄,即使你確定它們不存在。
所以如果你知道你要聯合的記錄集里沒有重復,那么你要使用UNION ALL,而不是UNION。UNION ALL聯合記錄集,但不搜索重復記錄,這樣減少SQLServer資源的使用,從而提升性能。
3 盡量不用SELECT * : 絕大多數情況下,不要用 * 來代替查詢返回的字段列表,用 * 的好處是代碼量少、就算是表結構或視圖的列發生變化,編寫的查詢SQL語句也不用變,都返回所有的字段。但數據庫服務器在解析時,如果碰到 *,則會先分析表的結構,然后把表的所有字段名再羅列出來。
這就增加了 分析的時間。 4 慎用SELECT DISTINCT: DISTINCT子句僅在特定功能的時候使用,即從記錄集中排除重復記錄的時候。
這是因為DISTINCT子句先獲取結果集然后去重,這樣增加SQLServer有用資源的使用。當然,如果你需要去做,那就只有去做了。
當如果你知道SELECT語句將從不返回重復記錄,那么使用DISTINCT語句對SQLServer資源不必要的浪費。 5 少用游標: 任何一種游標都會降低SQLServer性能。
有些情況不能避免,大多數情況可以避免。所以如果你的應用程序目前正在使用TSQL游標,看看這些代碼是否能夠重寫以避免它們。
如果你需要一行一行的執行操作,考慮下邊這些選項中的一個或多個來代替游標的使用: 使用臨時表 使用WHILE循環 使用派生表 使用相關子查詢 使用CASE語句 使用多個查詢 上面每一個都能取代游標并且執行更快。 如果你不能避免使用游標,至少試著提高它們的速度,找出加速游標的方法。
6 選擇最有效率的表名順序: SQLSERVER的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最后的表(基礎表driving table)將被最先處理,在FROM子句中包含多個表的情況下,必須選擇記錄條數最少的表作為基礎表,當SQLSERVER處理多個表時,會運用排序及合并的方式連接它們。首先 ,掃描第一個表(FROM子句中最后的那個表)并對記錄進行排序;然后掃描第二個表(FROM子句中最后第二個表);最后將所有從第二個表中檢索出的記錄與第一個表中合適記錄進行合并。
例如: 表 TAB1有 16384 條記錄,表 TAB2 有5條記錄,選擇TAB2作為基礎表 (最好的方法): select count(*) from TAB1 a, TAB2 b 選擇TAB1作為基礎表 (不佳的方法): select count(*) from TAB2 a, TAB1 b 如果有3個以上的表連接查詢,那就需要選擇交叉表(intersection table)作為基礎表,交叉表是指那個被其他表所引用的表。 7 使用表的別名(Alias): 當在SQL語句中連接多個表時,請使用表的別名并把別名前綴于每個Column上,這樣可以減少解析的時間并減少那些由Column歧義引起的語法錯誤。
8 SARG你的WHERE條件: ARGE來源于"Search Argument"(搜索參數)的首字母拼成的"SARG",它是指WHERE子句里,列和常量的比較。如果WHERE子句是sargable(可SARG的),這意味著它能利用索引加速查詢的完成。
如果WHERE子句不是可SARG的,這意味著WHERE子句不能利用索引(或至少部分不能利用), 執行的是全表或索引掃描,這會引起查詢的性能下降。 在WHERE子句里不可SARG的搜索條件如"IS NULL", "<>", "!=", "!>", "!<", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE"和"LIKE '%500'",通常(但不總是)會阻止查詢優化器使用索引執行搜索。
另外在列上使用包括函數的表達式、兩邊都使用相同列的表達式、或和一個列(不是常 量)比較的表達式,都是不可SARG的。 并不是每一個不可SARG的WHERE子句都注定要全表掃描。
如果WHERE子句包括兩個可SARG和一個不可SARG的子句,那么至少可SARG的子句能使用索引(如果存在的話)幫助快速訪問數據。 大多數情況下,如果表上有包括查詢里所有SELECT、JOIN、WHERE子句用到的列的覆蓋索引,那么覆蓋索引能夠代替全表掃描去返回查詢的數據,即使它有不可SARG的WHERE子句。
但記住覆蓋索引尤其自身的缺陷,如此經常產生寬索引會增加讀磁盤I/O。某些情況下,可以把不可SARG的WHER E子句重寫成可SARG的子句。
例如: WHERE SUBSTRING(firstname,1,1) = 'm' 可以寫成: WHERE firstname 。
如何優化sql語句
一、問題的提出 在應用系統開發初期,由于開發數據庫數據比較少,對于查詢SQL語句,復雜視圖的的編寫等體會不出SQL語句各種寫法的性能優劣,但是如果將應用系統提交實際應用后,隨著數據庫中數據的增加,系統的響應速度就成為目前系統需要解決的最主要的問題之一。
系統優化中一個很重要的方面就是SQL語句的優化。對于海量數據,劣質SQL語句和優質SQL語句之間的速度差別可以達到上百倍,可見對于一個系統不是簡單地能實現其功能就可,而是要寫出高質量的SQL語句,提高系統的可用性。
在多數情況下,Oracle使用索引來更快地遍歷表,優化器主要根據定義的索引來提高性能。但是,如果在SQL語句的where子句中寫的SQL代碼不合理,就會造成優化器刪去索引而使用全表掃描,一般就這種SQL語句就是所謂的劣質SQL語句。
在編寫SQL語句時我們應清楚優化器根據何種原則來刪除索引,這有助于寫出高性能的SQL語句。 二、SQL語句編寫注意問題 下面就某些SQL語句的where子句編寫中需要注意的問題作詳細介紹。
在這些where子句中,即使某些列存在索引,但是由于編寫了劣質的SQL,系統在運行該SQL語句時也不能使用該索引,而同樣使用全表掃描,這就造成了響應速度的極大降低。 1. IS NULL 與 IS NOT NULL 不能用null作索引,任何包含null值的列都將不會被包含在索引中。
即使索引有多列這樣的情況下,只要這些列中有一列含有null,該列就會從索引中排除。也就是說如果某列存在空值,即使對該列建索引也不會提高性能。
任何在where子句中使用is null或is not null的語句優化器是不允許使用索引的。 2. 聯接列 對于有聯接的列,即使最后的聯接值為一個靜態值,優化器是不會使用索引的。
我們一起來看一個例子,假定有一個職工表(employee),對于一個職工的姓和名分成兩列存放(FIRST_NAME和LAST_NAME),現在要查詢一個叫比爾.克林頓(Bill Cliton)的職工。 下面是一個采用聯接查詢的SQL語句, select * from employss where first_name||''||last_name ='Beill Cliton'; 上面這條語句完全可以查詢出是否有Bill Cliton這個員工,但是這里需要注意,系統優化器對基于last_name創建的索引沒有使用。
當采用下面這種SQL語句的編寫,Oracle系統就可以采用基于last_name創建的索引。 *** where first_name ='Beill' and last_name ='Cliton'; . 帶通配符(%)的like語句 同樣以上面的例子來看這種情況。
目前的需求是這樣的,要求在職工表中查詢名字中包含cliton的人。可以采用如下的查詢SQL語句: select * from employee where last_name like '%cliton%'; 這里由于通配符(%)在搜尋詞首出現,所以Oracle系統不使用last_name的索引。
在很多情況下可能無法避免這種情況,但是一定要心中有底,通配符如此使用會降低查詢速度。然而當通配符出現在字符串其他位置時,優化器就能利用索引。
在下面的查詢中索引得到了使用: select * from employee where last_name like 'c%'; 4. Order by語句 ORDER BY語句決定了Oracle如何將返回的查詢結果排序。Order by語句對要排序的列沒有什么特別的限制,也可以將函數加入列中(象聯接或者附加等)。
任何在Order by語句的非索引項或者有計算表達式都將降低查詢速度。 仔細檢查order by語句以找出非索引項或者表達式,它們會降低性能。
解決這個問題的辦法就是重寫order by語句以使用索引,也可以為所使用的列建立另外一個索引,同時應絕對避免在order by子句中使用表達式。 5. NOT 我們在查詢時經常在where子句使用一些邏輯表達式,如大于、小于、等于以及不等于等等,也可以使用and(與)、or(或)以及not(非)。
NOT可用來對任何邏輯運算符號取反。下面是一個NOT子句的例子: 。
where not (status ='VALID') 如果要使用NOT,則應在取反的短語前面加上括號,并在短語前面加上NOT運算符。NOT運算符包含在另外一個邏輯運算符中,這就是不等于(<>)運算符。
換句話說,即使不在查詢where子句中顯式地加入NOT詞,NOT仍在運算符中,見下例: 。 where status <>'INVALID'; 對這個查詢,可以改寫為不使用NOT: select * from employee where salary<3000 or salary>3000; 雖然這兩種查詢的結果一樣,但是第二種查詢方案會比第一種查詢方案更快些。
第二種查詢允許Oracle對salary列使用索引,而第一種查詢則不能使用索引。 雖然這兩種查詢的結果一樣,但是第二種查詢方案會比第一種查詢方案更快些。
第二種查詢允許Oracle對salary列使用索引,而第一種查詢則不能使用索引。