SQL語句優化技術分析
翻譯:Jerry [2005-11-11]
原文出處:http://www.51testing.com
原文作者:不詳
轉載請註明:來自Sawin系統分析之窗
操作符優化
IN 操作符
用IN寫出來的SQL的優點是比較容易寫及清晰易懂,這比較適合現代軟體開發的風格。
但是用IN的SQL性能總是比較低的,從ORACLE執行的步驟來分析用IN的SQL與不用IN的SQL有以下區別:
ORACLE試圖將其轉換成多個表的連接,如果轉換不成功則先執行IN裡面的子查詢,再查詢外層的表記錄,如果轉換成功則直接採用多個表的連接方式查詢。由此可見用IN的SQL至少多了一個轉換的過程。一般的SQL都可以轉換成功,但對於含有分組統計等方面的SQL就不能轉換了。
推薦方案:在業務密集的SQL當中盡量不採用IN操作符。
NOT IN操作符
此操作是強列推薦不使用的,因為它不能應用表的索引。
推薦方案:用NOT EXISTS 或(外連接+判斷為空)方案代替
<> 操作符(不等於)
不等於操作符是永遠不會用到索引的,因此對它的處理只會產生全表掃描。
推薦方案:用其它相同功能的操作運算代替,如
a<>0 改為 a>0 or a<0
a<>』』 改為 a>』』
IS NULL 或IS NOT NULL操作(判斷欄位是否為空)
判斷欄位是否為空一般是不會應用索引的,因為B樹索引是不索引空值的。
推薦方案:
用其它相同功能的操作運算代替,如
a is not null 改為 a>0 或a>』』等。
不允許欄位為空,而用一個預設值代替空值,如業擴申請中狀態欄位不允許為空,預設為申請。
建立點陣圖索引(有分區的表不能建,點陣圖索引比較難控制,如欄位值太多索引會使性能下降,多人更新操作會增加數據塊鎖的現象)
> 及 < 操作符(大於或小於操作符)
大於或小於操作符一般情況下是不用調整的,因為它有索引就會採用索引查找,但有的情況下可以對它進行優化,如一個表有100萬記錄,一個數值型欄位A,30萬記錄的A=0,30萬記錄的A=1,39萬記錄的A=2,1萬記錄的A=3。那麼執行A>2與A>=3的效果就有很大的區別了,因為A>2時ORACLE會先找出為2的記錄索引再進行比較,而A>=3時ORACLE則直接找到=3的記錄索引。
LIKE操作符
LIKE操作符可以應用通配符查詢,裡面的通配符組合可能達到幾乎是任意的查詢,但是如果用得不好則會產生性能上的問題,如LIKE 『%5400%』 這種查詢不會引用索引,而LIKE 『X5400%』則會引用范圍索引。一個實際例子:用YW_YHJBQK表中營業編號後面的戶標識號可來查詢營業編號 YY_BH LIKE 『%5400%』 這個條件會產生全表掃描,如果改成YY_BH LIKE 』X5400%』 OR YY_BH LIKE 』B5400%』 則會利用YY_BH的索引進行兩個范圍的查詢,性能肯定大大提高。
UNION操作符
UNION在進行表鏈接後會篩選掉重復的記錄,所以在表鏈接後會對所產生的結果集進行排序運算,刪除重復的記錄再返回結果。實際大部分應用中是不會產生重復的記錄,最常見的是過程表與歷史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
這個SQL在運行時先取出兩個表的結果,再用排序空間進行排序刪除重復的記錄,最後返回結果集,如果表數據量大的話可能會導致用磁碟進行排序。
推薦方案:採用UNION ALL操作符替代UNION,因為UNION ALL操作只是簡單的將兩個結果合並後就返回。
select * from gc_dfys
union all
select * from ls_jg_dfys
SQL書寫的影響
同一功能同一性能不同寫法SQL的影響
如一個SQL在A程序員寫的為
Select * from zl_yhjbqk
B程序員寫的為
Select * from dlyx.zl_yhjbqk(帶表所有者的前綴)
C程序員寫的為
Select * from DLYX.ZLYHJBQK(大寫表名)
D程序員寫的為
Select * from DLYX.ZLYHJBQK(中間多了空格)
以上四個SQL在ORACLE分析整理之後產生的結果及執行的時間是一樣的,但是從ORACLE共享內存SGA的原理,可以得出ORACLE對每個SQL 都會對其進行一次分析,並且佔用共享內存,如果將SQL的字元串及格式寫得完全相同則ORACLE只會分析一次,共享內存也只會留下一次的分析結果,這不僅可以減少分析SQL的時間,而且可以減少共享內存重復的信息,ORACLE也可以准確統計SQL的執行頻率。
WHERE後面的條件順序影響
WHERE子句後面的條件順序對大數據量表的查詢會產生直接的影響,如
Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1
Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1KV以下'
以上兩個SQL中dy_dj(電壓等級)及xh_bz(銷戶標志)兩個欄位都沒進行索引,所以執行的時候都是全表掃描,第一條SQL的dy_dj = '1KV以下'條件在記錄集內比率為99%,而xh_bz=1的比率只為0.5%,在進行第一條SQL的時候99%條記錄都進行dy_dj及xh_bz的比較,而在進行第二條SQL的時候0.5%條記錄都進行dy_dj及xh_bz的比較,以此可以得出第二條SQL的CPU佔用率明顯比第一條低。
查詢表順序的影響
在FROM後面的表中的列表順序會對SQL執行性能影響,在沒有索引及ORACLE沒有對表進行統計分析的情況下ORACLE會按表出現的順序進行鏈接,由此因為表的順序不對會產生十分耗伺服器資源的數據交叉。(註:如果對表進行了統計分析,ORACLE會自動先進小表的鏈接,再進行大表的鏈接)
SQL語句索引的利用
對操作符的優化(見上節)
對條件欄位的一些優化
採用函數處理的欄位不能利用索引,如:
substr(hbs_bh,1,4)=』5400』,優化處理:hbs_bh like 『5400%』
trunc(sk_rq)=trunc(sysdate), 優化處理:
sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)
進行了顯式或隱式的運算的欄位不能進行索引,如:
ss_df+20>50,優化處理:ss_df>30
『X』||hbs_bh>』X5400021452』,優化處理:hbs_bh>』5400021542』
sk_rq+5=sysdate,優化處理:sk_rq=sysdate-5
hbs_bh=5401002554,優化處理:hbs_bh=』 5401002554』,註:此條件對hbs_bh 進行隱式的to_number轉換,因為hbs_bh欄位是字元型。
條件內包括了多個本表的欄位運算時不能進行索引,如:
ys_df>cx_df,無法進行優化
qc_bh||kh_bh=』5400250000』,優化處理:qc_bh=』5400』 and kh_bh=』250000』
應用ORACLE的HINT(提示)處理
提示處理是在ORACLE產生的SQL分析執行路徑不滿意的情況下要用到的。它可以對SQL進行以下方面的提示
目標方面的提示:
COST(按成本優化)
RULE(按規則優化)
CHOOSE(預設)(ORACLE自動選擇成本或規則進行優化)
ALL_ROWS(所有的行盡快返回)
FIRST_ROWS(第一行數據盡快返回)
執行方法的提示:
USE_NL(使用NESTED LOOPS方式聯合)
USE_MERGE(使用MERGE JOIN方式聯合)
USE_HASH(使用HASH JOIN方式聯合)
索引提示:
INDEX(TABLE INDEX)(使用提示的表索引進行查詢)
其它高級提示(如並行處理等等)
ORACLE的提示功能是比較強的功能,也是比較復雜的應用,並且提示只是給ORACLE執行的一個建議,有時如果出於成本方面的考慮ORACLE也可能不會按提示進行。根據實踐應用,一般不建議開發人員應用ORACLE提示,因為各個資料庫及伺服器性能情況不一樣,很可能一個地方性能提升了,但另一個地方卻下降了,ORACLE在SQL執行分析方面已經比較成熟,如果分析執行的路徑不對首先應在資料庫結構(主要是索引)、伺服器當前性能(共享內存、磁碟文件碎片)、資料庫對象(表、索引)統計信息是否正確這幾方面分析。
⑵ 如何優化SQL2000資料庫
總結優化如下:
1、主鍵就是聚集索引
2、只要建立索引就能顯著提高查詢速度
3、把所有需要提高查詢速度的欄位都加進聚集索引,以提高查詢速度
(四)其他書上沒有的索引使用經驗總結
1、用聚合索引比用不是聚合索引的主鍵速度快
2、用聚合索引比用一般的主鍵作order by時速度快,特別是在小數據量情況下
3、使用聚合索引內的時間段,搜索時間會按數據占整個數據表的百分比成比例減少,而無論聚合索引使用了多少個
4 、日期列不會因為有分秒的輸入而減慢查詢速度
(五)其他注意事項
1. 不要索引常用的小型表
2. 不要把社會保障號碼(SSN)或身份證號碼(ID)選作鍵
3. 不要用用戶的鍵
4. 不要索引 memo/notes 欄位和不要索引大型文本欄位(許多字元)
5. 使用系統生成的主鍵
二、改善SQL語句
1、Like語句是否屬於SARG取決於所使用的通配符的類型
2、or 會引起全表掃描
3、非操作符、函數引起的不滿足SARG形式的語句
4、IN 的作用相當與OR
5、盡量少用NOT
6、exists 和 in 的執行效率是一樣的
7、用函數charindex()和前面加通配符%的LIKE執行效率一樣
8、union並不絕對比or的執行效率高
9、欄位提取要按照「需多少、提多少」的原則,避免「select *」
10、count(*)不比count(欄位)慢
11、order by按聚集索引列排序效率最高
12、高效的TOP
⑶ sql sever2000資料庫操作卡的問題
1看你運行SQL server 2000 伺服器的配置 如果是單機的,就要看你電腦的配置了。
2.配置沒問題的話,是遠程訪問資料庫伺服器要看下 網速如何
3.查詢操作的時候 一定要優化SQL 語句,例如查詢一個表,一般會select * from table 但是為了節省資源,建議查詢 select column1,column2,columnN from table 能夠快些
⑷ sql2000訪問速度慢
SQL Server資料庫查詢速度慢的原因有很多,常見的有以下幾種:
1、沒有索引或者沒有用到索引(這是查詢慢最常見的問題,是程序設計的缺陷)
2、I/O吞吐量小,形成了瓶頸效應。
3、沒有創建計算列導致查詢不優化。
4、內存不足
5、網路速度慢
6、查詢出的數據量過大(可以採用多次查詢,其他的方法降低數據量)
7、鎖或者死鎖(這也是查詢慢最常見的問題,是程序設計的缺陷)
8、sp_lock,sp_who,活動的用戶查看,原因是讀寫競爭資源。
9、返回了不必要的行和列
10、查詢語句不好,沒有優化
●可以通過以下方法來優化查詢 :
1、把數據、日誌、索引放到不同的I/O設備上,增加讀取速度,以前可以將Tempdb應放在RAID0上,SQL2000不在支持。數據量(尺寸)越大,提高I/O越重要。
2、縱向、橫向分割表,減少表的尺寸(sp_spaceuse)
3、升級硬體
4、根據查詢條件,建立索引,優化索引、優化訪問方式,限制結果集的數據量。注意填充因子要適當(最好是使用默認值0)。索引應該盡量小,使用位元組數小的列建索引好(參照索引的創建),不要對有限的幾個值的欄位建單一索引如性別欄位。
5、提高網速。
6、擴大伺服器的內存,Windows 2000和SQL server 2000能支持4-8G的內存。
配置虛擬內存:虛擬內存大小應基於計算機上並發運行的服務進行配置。運行 Microsoft SQL Server? 2000時,可考慮將虛擬內存大小設置為計算機中安裝的物理內存的1.5倍。如果另外安裝了全文檢索功能,並打算運行Microsoft搜索服務以便執行全文索引和查詢,可考慮:將虛擬內存大小配置為至少是計算機中安裝的物理內存的3倍。將SQL Server max server memory伺服器配置選項配置為物理內存的1.5倍(虛擬內存大小設置的一半)。
7、增加伺服器CPU個數;但是必須 明白並行處理串列處理更需要資源例如內存。使用並行還是串列程是MsSQL自動評估選擇的。單個任務分解成多個任務,就可以在處理器上運行。例如耽擱查詢 的排序、連接、掃描和GROUP BY字句同時執行,SQL SERVER根據系統的負載情況決定最優的並行等級,復雜的需要消耗大量的CPU的查詢最適合並行處理。但是更新操作UPDATE,INSERT, DELETE還不能並行處理。
8、如果是使用like進行查詢的話,簡單的使用index是不行的,但是全文索引,耗空間。 like ''a%'' 使用索引 like ''%a'' 不使用索引用 like ''%a%'' 查詢時,查詢耗時和欄位值總長度成正比,所以不能用CHAR類型,而是VARCHAR。對於欄位的值很長的建全文索引。
9、DB Server 和APPLication Server 分離;OLTP和OLAP分離
10、分布式分區視圖可用於實現資料庫伺服器聯合體。
聯合體是一組分開管理的伺服器,但它們相互協作分擔系統的處理負荷。這種通過分區數據形成資料庫伺服器聯合體的機制能夠擴大一組伺服器,以支持大型的多層 Web 站點的處理需要。有關更多信息,參見設計聯合資料庫伺服器。(參照SQL幫助文件''分區視圖'')
a、在實現分區視圖之前,必須先水平分區表
b、 在創建成員表後,在每個成員伺服器上定義一個分布式分區視圖,並且每個視圖具有相同的名稱。這樣,引用分布式分區視圖名的查詢可以在任何一個成員伺服器上 運行。系統操作如同每個成員伺服器上都有一個原始表的復本一樣,但其實每個伺服器上只有一個成員表和一個分布式分區視圖。數據的位置對應用程序是透明的。
11、重建索引 DBCC REINDEX ,DBCC INDEXDEFRAG,收縮數據和日誌 DBCC SHRINKDB,DBCC SHRINKFILE. 設置自動收縮日誌.對於大的資料庫不要設置資料庫自動增長,它會降低伺服器的性能。
在T-sql的寫法上有很大的講究,下面列出常見的要點:首先,DBMS處理查詢計劃的過程是這樣的:
1、 查詢語句的詞法、語法檢查
2、 將語句提交給DBMS的查詢優化器
3、 優化器做代數優化和存取路徑的優化
4、 由預編譯模塊生成查詢規劃
5、 然後在合適的時間提交給系統處理執行
6、 最後將執行結果返回給用戶。
其次,看一下SQL SERVER的數據存放的結構:一個頁面的大小為8K(8060)位元組,8個頁面為一個盤區,按照B樹存放。
⑸ SQL2000數據使用了10年了,現在系統越來越慢,如何提高資料庫的速度及效率。
如果不想改動太大,不生產的進修,就checkdb一下,所有表索引重建一下,性能會提高一些。
進一步的話,就是查找一下慢的查詢,優化一下表的索引。
⑹ 如何優化2000萬級資料庫sql server資料庫性能
掃描計數:索引和表執行次數
邏輯讀取:數據緩存中讀取的頁數
物理讀取:從磁碟中讀取的頁數
預讀:查詢過程中,從磁碟放入緩存的頁數
lob邏輯讀取:從數據緩存中讀取image、text、ntext或大型數據的頁數
lob物理讀取:從磁碟中讀取image、text、ntext或大型數據的頁數
lob預讀:查詢過程中,從磁碟放入緩存的image、text、ntext或大型數據的頁數
如果物理讀取次數和預計次數比較多,可以使用索引進行優化。
⑺ SQL2000資料庫,如何提高對一個龐大的表的查詢速度
你經常查詢的,經常分組的,經常判斷的
欄位
,必須加
索引
,增加索引後,查詢速度會大幅度提高,但是插入,更新,刪除速度會變慢,總而言之,總有一個慢,你權衡是數據插入,更新,刪除多還是查詢多,決定是否增加索引,非經常查詢欄位就不要增加索引了,以免浪費
數據空間
和增加插入,更新,刪除的時間
另外,如果數據按時間增長,由於你使用的是SQL2000,建議將
大表
拆開每日保存一張
日表
,縮小單張表的大小,在表內查詢就會快很多(因為讀進
內存
的數據小多了),實現分區的功能;如果使用SQL2005,則資料庫可以直接支持分區
這樣就
沒有問題
了,我們這處理的數據每天4000
萬行
,保存了50天數據,查詢起來也只要5分鍾