當前位置:首頁 » 數據倉庫 » sql資料庫優化案例分享
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

sql資料庫優化案例分享

發布時間: 2022-05-12 11:13:28

A. sql server 安全,性能優化的15條方案

1.1 基本概念 與資料庫技術密切相關的基本概念包括:數據、資料庫、資料庫管理系統和資料庫系統四大概念。1. 數據(Data) 數據是對客觀事物的一種描述,是由能被計算機識別與處理的數值、字元等符號構成的集合,即數據是指描述事物的符號記錄。 廣義地說,數據是一種物理符號的序列,用於記錄事物的情況,是對客觀事物及其屬性進行的一種抽象化及符號化的描述。數據的概念應包括數據的內容和形式兩個方面。數據的內容是指所描述的客觀事物的具體特性,也就是通常所說的數據的「值」;數據的形式則是指數據內容所存儲的具體形式,即數據的「類型」。故此,數據可以用數據類型和值來表示。2. 資料庫(Data Base,DB) 資料庫是指長期存儲在計算機內部、有組織的、可共享的數據集合,即在計算機系統中按一定的數據模型組織、存儲和使用的相關聯的數據集合成為資料庫。 資料庫中的數據按照一定的數據模型組織、描述和存儲,具有較小的冗餘度、較高的數據獨立性、易擴展性、集中性和共享性,以文件的形式存儲在存儲介質上的。資料庫中的數據由資料庫管理系統進行統一管理和控制,用戶對資料庫進行的各種數據操作都是通過資料庫管理系統實現。3. 資料庫管理系統(Data Base Management System,DBMS) 資料庫管理系統是資料庫系統的核心,是為資料庫的建立、使用和維護而配置的軟體,是位於操作系統與用戶之間的一層數據管理軟體。主要功能是對資料庫進行定義、操作、控制和管理。1) 數據定義 數據的定義包括:定義構成資料庫結構的外模式、模式和內模式,定義各個外模式和模式之間的映射,定義模式與內模式之間的映射,定義有關的約束條件。2) 數據處理對數據的處理操作主要包括對資料庫數據的檢索、插入、修改和刪除等基本操作。3) 安全管理 對資料庫的安全管理主要體現在:對資料庫進行並發控制、安全性檢查、完整性約束條件的檢查和執行、資料庫的內部維護(如索引、數據字典的自動維護)等。並且能夠管理和監督用戶的許可權,防止擁護有任何破壞或者惡意的企圖。4) 數據的組織、存儲和管理 負責分類地組織、存儲和管理資料庫數據,確定以何種文件結構和存取方式物理地組織數據,如何實現數據之間的聯系,以便提高存儲空間利用以及提高隨機查找、順序查找、增加、刪除和查改等操作的時間效率。5) 建立和維護資料庫 建立資料庫包括資料庫數據的初始化與數據轉換等。維護資料庫包括資料庫的轉儲與恢復、資料庫的重組織與重構造、性能的監視與分析等。6) 數據通信介面提供與其他軟體系統進行通信的功能。4. 資料庫系統(Data Base System,DBS) 資料庫系統指在計算機系統中引入資料庫後的系統構成,一般有資料庫、資料庫管理系統、應用系統、資料庫管理員和用戶構成。1.2 資料庫系統的特點 資料庫系統的點主要有:數據的結構化、高共享性、低冗餘度、易擴充、較高的獨立性(物理數據獨立、邏輯數據獨立)以及數據由DBMS統一管理和控制(數據的安全性Security保護、數據的完整性Integrity保護、並發Concurrency控制、資料庫恢復Recovery)等。第二章 資料庫性能優化 資料庫作為一種獨立的、有組織、的可共享的數據集合,數據的查詢訪問是數據操作中頻度最高的操作。當數據量和訪問頻率達到一定程度的時候,系統的響應速度就至關重要了,這時候就需要對資料庫數據存儲的結構和方式進行優化,使其滿足系統需要的訪問響應速度。2.1 性能影響因素 常見的影響數據訪問速度的因素,有以下幾種:1. 沒有索引或者沒有用到索引 資料庫索引就像書籍中目錄一樣,使用戶在訪問資料庫數據時,不必遍歷所有數據就可以找到需要的數據。創建索引後,可以保證每行數據的唯一性,極大地提高數據檢索效率,這是一中犧牲空間換取性能的方法。沒有索引或者沒有用到索引是數據訪問速度慢最常見的因素,也是程序設計的一個缺陷所在。2. I/O吞吐量小,形成了瓶頸效應 I/O吞吐量是影響數據訪問速度的客觀因素(硬體因素)。在一定的硬體環境下,利用優化的部署方案可適當提高I/O吞吐量。3. 沒有創建計算列導致查詢不優化 計算列是一個比較特殊的列,不填寫任何設計類型,用戶不可以改變該列的值。計算列的值是通過一定的函數公式等以另一個或多個列的值為輸入值計算出的結果。如果沒相應的計算列,在一些數據查詢的時候需要對已有數據進行計算,從而浪費一部分性能。4. 內存不足 對資料庫數據的查詢訪問毫無疑問會佔用大量的內存空間,當內存不足的情況下,數據的訪問速度會受到明顯的影響甚至訪問出現超時情況,是影響數據訪問速度的客觀因素。5. 網路速度慢 網路速度慢是影響數據訪問速度的客觀因素。可通過提高網路訪問的位寬來解決。6. 查詢出的數據量過大 當查詢出的數據量過大時,內存的佔用、系統時間的佔用等都影響數據訪問的速度。可以採用多次查詢、定位查詢、和查詢數據量控制來解決。7. 鎖或者死鎖 鎖或者死鎖在資料庫數據訪問時會造成訪問者等待時間過程或者永久無法獲取到資源。這是查詢慢最常見的因素之一,是程序設計的缺陷,要盡量避免。8. 返回不必要的行和列 在一般的數據查詢中,都盡可能多的獲取數據信息,這樣造成了不必要的數據遍歷,大大的增加了數據訪問的響應的時間。所以在一般的查詢中,盡量查詢少的行和列,將數據遍歷時間降到最低以滿足數據輸出需求。9. 查詢語句不夠優化 在數據查詢訪問過程中,使用最頻繁的是使用自定義的查詢語句進行數據輸出的。所以編寫優化的查詢語句能夠很大程度上提高數據查詢訪問的速度。2.2 性能優化 資料庫性能優化主要是提高數據訪問的速度,即提高資料庫響應速度的性能指標。性能優化主要分為主觀因素和客觀因素兩部分的優化。這里主要針對影響性能的客觀因素進行優化。2.2.1 主觀因素優化 主觀因素主要是指伺服器的硬體環境。主要優化有以下幾個方面:1、 把數據、日誌、索引放到不同的I/O設備上,增加讀取速度,數據量越大,提高I/O吞吐量越重要;2、 縱向、橫向分割表,減少表的尺寸(sp_spaceuse);3、 升級硬體;4、 提高網路訪問速度;5、 擴大伺服器的內存;配置虛擬內存:虛擬內存大小應基於計算機上並發運行的服務進行配置,一般設置為物理內存的1.5倍;如果安裝了全文檢索功能,並打算運行Microsoft搜索服務以便執行全文索引和查詢,可考慮將虛擬內存大小設置為至少計算機中物理內存的3倍;6、 增加伺服器CPU個數;其中並行處理比串列處理更需要資源。SQL SERVER根據系統負載情況決定最優的並行等級,復雜的需要消耗大量的CPU的查詢適合並行處理。不過更新操作UPDATE、INSERT、DELETE不能進行並行處理。 2.2.2 客觀因素優化 客觀因素主要指的是由於設計和開發中存在的缺陷和漏洞;主要優化有以下幾個方面:1. 優化索引(1) 根據查詢條件建立優化的索引、優化訪問方式,限制結果集的數據量。注意填充因子要適當(最好是使用默認值0)。索引應該盡量小,使用位元組數小的列建里索引(參照索引的創建),不要對有限的幾個值的欄位建立單一索引(如性別欄位)。(2) 如果使用LIKE進行查詢的話,簡單的使用INDEX是不行的,全文索引又太耗費空間。LIKE 『N%』使用索引,LIKE 『%N』不使用索引。用LIKE『%N%』查詢時,查詢耗時和欄位值總長度成正比,所以不能用CHAR類型而採用VARCHAR。對於欄位的值很長的欄位建立全文索引。(3) 重建索引DBCC REINDEX,DBCC INDEXDEFRAG,收縮數據和日誌DBCC SHRINKDB,DBCC SHRINKFILE。設置自動收縮日誌,對與大的資料庫不要設置資料庫自動增長,它會降低伺服器的性能。2. 資料庫部署優化(1) DB SERVER和APPLICATION SERVER分離,OLTP和OLAP分離;(2) 使用分區視圖。分布式分區視圖可用於實現資料庫伺服器聯合體,聯合體是一組分開管理的伺服器,他們互相協作分擔系統的處理負荷。A、在實現分區視圖之前,必須先水平分區表。B、在創建成員表後,在每個伺服器上定義一個分布式分區視圖,並且每個視圖具有相同的名稱。這樣引用分布式分區視圖名的查詢可以在任何一個成員伺服器上運行。系統操作如同每個成員伺服器都有一個原始表的復本一樣,不過每個伺服器上其實只有一個成員表和一個分布式分區視圖。數據的位置對應用程序是透明的。3. 查詢語句優化 T-SQL的寫法上有很大的講究,DBMS處理查詢計劃的過程是:a、查詢語句的詞法、語法檢查;b、將語句提交給DBMS的查詢優化器;c、優化器做代數優化和存取路徑的優化;d、由預編譯模塊生成查詢規劃;e、在合適的時間提交給系統處理執行;f、將執行結果返回給用戶。(1) COMMIT和ROLLBACK的區別:ROLLBACK回滾所有的事務;COMMIT提交當前的事務。在動態語句中寫事務,請將事務寫在外面,如:BEGIN TRAN EXEC(@SQL) COMMIT TRANS或者將動態SQL寫成函數或者存儲過程。(2) 在大數據兩的查詢輸出SELECT語句中盡量不要使用自定義函數,調用自定義函數的函數時系統調用是一個迭代過程,很影響查詢輸出性能的。在查詢欄位時盡可能使用小欄位兩輸出,並在WHERE子句或者使用SELECT TOP 10/1 PERCENT來限制返回的記錄數,使用SET ROWCOUNT來限制操作的記錄數,避免整表掃描。返回不必要的數據,不但浪費了伺服器的I/O資源,加重了網路的負擔,如果表很大的話,在表掃描期間將表鎖住,禁止其他的聯接訪問,後過很嚴重的。(3) SQL的注釋申明對執行查詢輸出沒有任何影響。(4) 使用計算列對數據進行簡單計算,盡量避免在查詢語句中對數據進行運算。(5) 盡可能不使用游標,它會佔用大量的資源。如果需要ROW-BY-ROW地執行,盡量採用非游標技術,如:客戶端循環、臨時表、TABLE變數、子查詢、CASE語句等等。(6) 使用PROFILER來跟蹤查詢,得到查詢所需的時間,找出SQL的問題所在,用索引優化器優化索引。(7) 注意UNION和UNION ALL的區別。在沒有必要的時候不要用DISINCT,它同UNION一樣會降低查詢速度,重復的記錄在查詢里是沒有問題的。(8) 用sp_configure 『query governor cost limit』或者 SET QUERY_COVERNOR_COST_LIMIT來限制查詢消耗的資源。當評估查詢消耗的 資源超出限制時,伺服器自動取消查詢,在查詢之前就扼殺掉。SET LOCKTIME 設置鎖的時間。(9) 不要在WHERE子句中列名加函數,如CONVERT,SUBSTRING等,如果必須用函數的時候,創建計算列在創建索引來替代。NOT IN會多次掃描表,使用EXISTS、NOT EXISTS、IN、LEFT OUTER JOIN來替代,其中EXISTS比IN更快,最慢的NOT操作。(10) 使用QUERY ANALYZER,查看SQL語句的查詢計劃和評估分析是否是優化的SQL。一般20%的代碼佔用了80%的資源,優化的重點就是這些慢的地方。(11) 如果使用了IN或者OR等時發現查詢沒有走索引,使用顯式申明指定索引,如:Select * From FA01(INDEX=IX_SEX) Where AA0107 IN(『01』,『02』)。(12) 在需要對已有數據進行比較復雜計算才能獲得查詢的結果數據時,將需要查詢的結果預先計算好放在表中,查詢的時候在SELECT。(13) 資料庫有一個原則是代碼離數據越近越好,所有有限選擇DEFAULT,依次為RULES,CONSTRAINT,PROCEDURE來編寫程序的質量高,速度快。如果要插入大的二進制到IMAGE列,使用存儲過程,千萬不要用內嵌INSERT直接插入。因為這樣應用程序首先將二進制轉換成字元串,伺服器收到字元後又將他轉換成二進制。存儲過程直接傳入二進制參數即可,處理速度明顯改善,如:CREATE PROCEDURE image_insert @image varbinary as Insert into table(fImage) values(@image)。(14) Between在某些時候比IN速度更快,更快地根據索引找到范圍。由於IN會比較多次,所以有時會慢些。(15) 盡量不要建沒有作用的事務例如產生報表時,浪費資源,只有在必須使用事務時才建立合適的事務。(16) 用OR的字句可以分解成多個查詢,並通過UNION連接多個查詢。速度取決與是否使用索引。如果查詢需要用聯合索引,用UNION ALL執行的效率更高些。(17) 盡量少用視圖,視圖的效率低。對視圖操作比直接對表操作慢,可以用SRORED PROCEDURE來代替。特別是不要用視圖嵌套,嵌套視圖增加了尋找原始資料的難度。視圖是存放在伺服器上的被優化好了的已經產生查詢規劃的SQL。對單表數據檢索時,不要使用指向多表的視圖,否則增加了不必要的系統開銷,查詢也會受到干擾。沒有必要時不要用DISTINCT和ORDER BY,這些動作可以改在客戶端執行,增加了額外的開銷,這同UNION和UNION ALL原理相同。(18) 當使用SELECT INTO和CREATE TABLE時,會鎖住系統表(SYSOBJECTS,SYSINDEXES等),從而阻塞其他的連接的存取。所以千萬不要在事務內部使用。如果經常要用到臨時表時請使用實表或者臨時表變數。盡量少用臨時表,用結果集和TABLE類型的變數來代替。(19) 在使用GROUP BY HAVING子句時,在使用前剔除多餘的行,盡量避免使用HAVING子句剔除行工作。剔除行最優的執行順序是:SELECT的WHERE子句選擇所有合適的行,GROUP

B. 什麼是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 like 'm%'

這兩個WHERE子句有相同的結果,但第一個是不可SARG的(因為使用了函數)將運行得慢些,而第二個是可SARG的,將運行得快些。

如果你不知道特定的WHERE子句是不是可SARG的,在查詢分析器里檢查查詢執行計劃。這樣做,你能很快的知道查詢是使用了索引還是全表掃描來返回的數據。仔細分析,許多不可SARG的查詢能寫成可SARG的查詢。下面分幾點講解WHERE條件的SARG。

8.1 WHERE子句中的連接順序
SQLSERVER採用自下而上的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他WHERE條件之前,那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾。例如:

(低效)

SELECT * FROM EMP E

WHERE SAL > 50000

AND JOB = 『MANAGER』

AND 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO)

(高效)

SELECT * FROM EMP E

WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO)

AND SAL > 50000

AND JOB = 『MANAGER』

8.2 避免困難的正規表達式:
MATCHES和LIKE關鍵字支持通配符匹配,技術上叫正規表達式。但這種匹配特別耗費時間。例如:

SELECT * FROM customer WHERE zipcode LIKE "98_ _ _"

即使在zipcode欄位上建立了索引,在這種情況下也還是採用順序掃描的方式。如果把語句改為SELECT * FROM customer WHERE zipcode >="98000",在執行查詢時就會利用索引來查詢,顯然會大大提高速度。

另外,還要避免非開始的子串。例如語句:

SELECT * FROM customer WHERE zipcode[2,3] >"80"

在where子句中採用了非開始子串,因而這個語句也不會使用索引。

8.3 避免對大型錶行數據的順序存取:
在嵌套查詢中,對表的順序存取對查詢效率可能產生致命的影響。比如採用順序存取策略,一個嵌套3層的查詢,如果每層都查詢1000行,那麼這個查詢就要查詢10億行數據。避免這種情況的主要方法就是對連接的列進行索引。例如,兩個表:學生表(學號、姓名、年齡……)和選課表(
學號、課程號、成績)。如果兩個表要做連接,就要在「學號」這個連接欄位上建立索引。

還可以使用並集來避免順序存取。盡管在所有的檢查列上都有索引,但某些形式的where子句強迫優化器使用順序存取。下面的查詢將強迫對orders表執行順序操作:

SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008

雖然在customer_num和order_num上建有索引,但是在上面的語句中優化器還是使用順序存取路徑掃描整個表。因為這個語句要檢索的是分離的行的集合,所以應該改為如下語句:

SELECT * FROM orders WHERE customer_num=104 AND order_num>1001

UNION ALL

SELECT * FROM orders WHERE order_num=1008

這樣就能利用索引路徑處理查詢。

8.4 EXISTS和IN的使用:
在許多基於基礎表的查詢中,為了滿足一個條件,往往需要對另一個表進行聯接。 在這種情況下,使用EXISTS(或NOT EXISTS)通常將提高查詢的效率。在子查詢中,NOT IN子句將執行一個內部的排序和合並。無論在哪種情況下,NOT IN都是最低效的,因為它對子查詢中的表執行
了一個全表遍歷。為了避免使用NOT IN,我們可以把它改寫成外連接(Outer Joins)或NOT EXISTS。

8.5 避免在索引列上使用IS NULL和IS NOT NULL:
避免在索引中使用任何可以為空的列,SQLSERVER將無法使用該索引。對於單列索引,如果列包含空值,索引中將不存在此記錄;對於復合索引,如果每個列都為空,索引中同樣不存在此記錄。如果至少有一個列不為空,則記錄存在於索引中。

如果唯一性索引建立在表的A列和B列上,並且表中存在一條記錄的A,B值為(123,null),SQLSERVER將不接受下一條具有相同A,B值(123,null)的記錄插入。

如果所有的索引列都為空,SQLSERVER將認為整個鍵值為空,而空不可能等於空,因此你可以插入1000條具有相同鍵值的記錄,當然它們都是空!因為空值不存在於索引列中,所以WHERE子句中對索引列進行空值比較將使SQLSERVER停用該索引。下面的代碼將會很低效(索引失效):

SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL

8.6 避免在索引列上使用計算:
WHERE子句中,如果索引列是函數的一部分,優化器將不使用索引而使用全表掃描。 例如下面的語句低效 :

SELECT … FROM DEPT WHERE SAL * 12 > 25000

而下面的語句將是高效的:

SELECT … FROM DEPT WHERE SAL > 25000/12

請務必注意,查詢中不要對索引列進行處理,如:TRIM,substring,convert等等操作。

8.7 用WHERE子句替換HAVING子句:
避免使用HAVING子句,HAVING只會在檢索出所有記錄之後才對結果集進行過濾,這個處理需要排序、統計等操作。如果能通過WHERE子句限制記錄的數目,那就能減少這方面的開銷。

9 避免或簡化排序:
應當簡化或避免對大型表進行重復的排序。當能夠利用索引自動以適當的次序產生輸出時,優化器就避免了排序的步驟。以下是一些影響因素:

l 索引中不包括一個或幾個待排序的列;

l group by或order by子句中列的次序與索引的次序不一樣;

l 排序的列來自不同的表。

為了避免不必要的排序,就要正確地增建索引,合理地合並資料庫表(盡管有時可能影響表的規范化,但相對於效率的提高是值得的)。如果排序不可避免,那麼應當試圖簡化它,如縮小排序的列的范圍等。

10 臨時表的使用:
臨時表有很多特殊的用途,象用來替代游標,不過它們仍能引起性能問題,如果這個問題能消除,SQLServer將執行得更快。在永久表和臨時表的數據行相同的條件下,使用臨時表沒有永久錶快。但有時還必須得使用臨時表,如先從存儲大量數據的永久表中提取符全條件的存放到臨時
表,然後在臨時表上執行操作。如果是直接在存儲大量數據的永久表上執行操作(如:統計、循環等),其性能將大打折扣。所以,使不使用臨時表,何時使用臨時表,需要具體情況決定。

11 是否使用視圖:
視圖最大的用途是處理安全相關的問題,而不是一些懶惰的開發人員用來存儲經常使用的查詢的方法。例如,如果你需要允許用戶訪問特定SQLServer的數據,那麼你也許可以考慮為用戶(或組)創建一個視圖,然後給用戶訪問視圖而不是基表的許可權。另一方面,在應用程序里,從視圖選
擇數據沒有好的理由,相反,繞過視圖直接從需要的表裡獲取數據。原因是許多視圖(當然不是全部)返回比SELECT語句所需更多的數據,增加不必要的開銷。

例如,假定有一個視圖從兩個連接表裡返回10列。你想要從視圖里使用SELECT語句返回其中7列。實際上發生的情況是基於視圖的查詢先運行,返回數據,然後你的查詢針對這些數據運行。既然你僅需要7列,而不是視圖返回的10列,更多不必要的數據被返回。浪費SQLServer的資源。

長久以來,大家在爭論是查詢視圖速度快還是直接查詢快,本人也不敢輕易下結論,因此作了多次試驗,其結果是:基於視圖查詢,性能確實不會比直接寫查詢語句快,對於簡單的查詢,最多是在同一水平上。

當然,上面的測試是在沒有為視圖創建索引的情況下,SQLServer2000以上可以為視圖創建索引,視圖索引與表的索引在作用方式上非常相似。與表一樣,視圖可以有一個集簇索引(clustered index)和多個非集簇索引。創建視圖索引後能夠提高視圖的性能。

如果視圖不包含索引,則資料庫中不保存視圖返回的結果集。有的時候,我們可能要創建涉及大量記錄或必須進行復雜計算的視圖,比如要進行聚合分組處理或多重連接操作。如果每次引用這些視圖的時候讓sql server重新生成結果集,資料庫開銷將非常大。

12 讓事務盡可能的短:
保持TSQL事務盡可能的短。這會幫助減少鎖(所有類型的鎖)的數量,有助於全面提升SQLServer的性能。如果有經驗,你也許要將長事務分成更小的事務組。

13 用存儲過程代替直接寫查詢語句:
存儲過程為開發人員提供了很多好處,包括:

n 減少網路流量和響應時間,提升應用程序性能。例如,通過網路發送一個存儲過程調用,而不是發送500行的TSQL將更快,資源使用更少。當每次執行SQL時,都會執行解析SQL語句、估算索引的利用率、綁定變數、讀數據塊等等工作。

n 存儲過程執行計劃能夠重用,駐留在SQLServer內存的緩存里,減少伺服器開銷。

n 客戶端執行請求更有效率。例如,如果應用程序需要插入大量的二進制值到一個image數據列而不使用存儲過程,它必須轉化二進制為字元串(大小會增加一倍),然後發送給SQLServer。當SQLServer接收到後,它必須把字元串值轉回二進制格式。大量的浪費開銷。存儲過程能
消除這個問題通過將應用程序傳給SQLServer的二進制格式作為參數,從而減少開銷提升性能。

n 存儲過程幫助提供代碼重用。雖然這些不直接提升應用程序的性能,通過減少代碼量和減少調試時間來提升開發人員的效率。

n 存儲過程能封裝邏輯。你能夠改變存儲過程代碼而不影響客戶端(假定你保持參數相同也不移除任何結果集的列)。這節約開發人員的時間。

n 存儲過程為你的數據提供更好的安全性。如果你僅使用存儲過程,你可以移除直接對表的SELECT、INSERT、UPDATE和DELETE許可權從而強迫開發人員使用存儲過程訪問數據。這會節約DBA的時間。

n 作為首要的常規,所有的TSQL代碼都應該通過存儲過程調用。

13.1 存儲過程名不要以 sp_ 開頭:
對這一準則,可能很多人會感覺納悶,是的,我開始也納悶過。如果創建的存儲過程不是運行在Master資料庫里,不要使用以sp_為前綴的名稱。這個特別的前綴是為系統存儲過程保留的。盡管使用這個前綴不會禁止用戶定義的存儲過程的運行,但會稍微降低一些執行效率。這是因為
SQLServer在執行以sp_為前綴的任何一個存儲過程時預設地首先試圖在Master資料庫里尋找,盡管那兒沒有,這就浪費了尋找存儲過程的時間。如果SQLServer在Master資料庫里不能找到存儲過程,那麼接下來會將存儲過程的擁有者作為DBO去解析。如果存儲過程在目前的資料庫里,那麼
它會執行。為了避免不必要的延遲,不要用前綴為sp_命名你的任何一個存儲過程。

13.2 存儲過程的擁有者要相同:
為了最好的性能,同一個存儲過程里調用的所有對象的擁有者都應該相同,DBO更適宜。如果不是那樣,即對象名相同而擁有者不同,那麼SQLServer必須執行名稱判斷。當發生這樣的情形時,SQLServer不能使用存儲過程里在內存里的執行計劃,相反,它必須重新編譯存儲過程,從而
影響性能。當從應用程序里調用存儲過程時,使用分隔符名稱來調用也是重要的。如:

EXEC dbo.myProcere

代替:

EXEC myProcere

這樣做有兩個原因,其中一個和性能有關。首先,使用完全有分隔符的名稱有助於消除那些和你要運行的存儲過程有潛在的混淆,有助於禁止BUG和潛在的問題。但更重要的是,這樣做SQLServer能更直接的訪問存儲過程執行計劃,而不是輪流訪問,從而加速了存儲過程的性能。當然性能
提升很小,但如果你的伺服器每小時要運行成千上萬或更多的存儲過程,這些節約的小段時間加起來就很可觀了。

14 完整性使用下的約束和觸發器:
資料庫里不要執行多餘的完整性特點。例如,如果你正使用主鍵和外鍵約束來強迫引用完整性,則不要添加觸發器來實現相同的功能而增加不必要的開銷。同樣既使用約束又使用默認值或既使用約束又使用規則也會執行多餘的工作。

15 在SQL中捕捉異常:
這一條准則應該不能算是優化方面的,只是編寫要求。現在SQLServer2005中,新增了BEGIN TRY…END TRY和 BEGIN CATCH…END CATCH二個成對語句,用於捕捉運行時出現的異常。在Oracle中,可用 BEGIN…EXCEPTION…END 語句捕捉異常。

把SQL代碼塊中加入捕捉異常的語句內,有二個好處:一是可以在SQL語句內部得到異常並作錯誤處理,如在錯誤代碼塊內返回自定義錯誤信息、ROLBACK等。這樣可減少應用程序捕捉異常帶來的資源開銷;另外一個好處就是可以防止死鎖情況的發生,當出現死鎖時,SQLServer2005會拋出
異常,我們就可捕捉到。

下面列出一些索引的概念,有助於設計表結構和編寫SQL語句:

按照存儲規則來分:

l 聚集索引:該索引中鍵值的邏輯順序決定了表中相應行的物理順序。因此一個表只能包含一個聚集索引,但該索引可以包含多個列(組合索引)。檢索效率比普通索引高,但對數據新增/修改/刪除的影響比較大。

l 非聚集索引:與聚集索引相對,不影響表中的數據存儲順序,檢索效率比聚集索引低,對數據新增/修改/刪除的影響很少。

按照維護與管理的角度來分:

l 唯一索引:惟一索引可以確保索引列不包含重復的值,可以用多個列,但是索引可以確保索引列中每個值組合都是唯一的。

l 主鍵索引:在資料庫關系圖中為表定義一個主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特殊類型。主鍵索引要求主鍵中的每個值是唯一的。當在查詢中使用主鍵索引時,它還允許快速訪問數據。

l 普通索引:由關鍵字KEY或INDEX定義的索引,唯一任務是加快對數據的訪問速度。因此,應該只為那些最經常出現在查詢條件或排序條件中的數據列創建索引。只要有可能,就應該選擇一個數據最整齊、最緊湊的數據列(如整數類型的數據列)來創建索引。允許有重復的列存在


l 復合索引:如果在兩上以上的列上創建的索引,則稱為復合索引。

C. 列舉sql優化有哪些方式方法 博客園

sql優化的方式有:

1、選擇最有效率的表名順序(只在基於規則的優化器中有效):

ORACLE 的解析器按照從右到左的順序處理FROM子句中的表名,FROM子句中寫在最後的表(基礎表 driving table)將被最先處理,在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎表。如果有3個以上的表連接查詢, 那就需要選擇交叉表(intersection table)作為基礎表, 交叉表是指那個被其他表所引用的表。

2、WHERE子句中的連接順序:

ORACLE採用自下而上的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他WHERE條件之前, 那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾。

3、SELECT子句中避免使用 『 * 『:

ORACLE在解析的過程中, 會將'*' 依次轉換成所有的列名, 這個工作是通過查詢數據字典完成的, 這意味著將耗費更多的時間 。

4、 減少訪問資料庫的次數:

ORACLE在內部執行了許多工作: 解析SQL語句, 估算索引的利用率, 綁定變數 , 讀數據塊等。

5、 在SQL*Plus , SQL*Forms和Pro*C中重新設置ARRAYSIZE參數, 可以增加每次資料庫訪問的檢索數據量 ,建議值為200 。

6、 使用DECODE函數來減少處理時間:

使用DECODE函數可以避免重復掃描相同記錄或重復連接相同的表。

7、整合簡單,無關聯的資料庫訪問:

如果你有幾個簡單的資料庫查詢語句,你可以把它們整合到一個查詢中(即使它們之間沒有關系)。

D. 如何優化sql資料庫

在資料庫應用系統中編寫可執行的SQL語句可以有多種方式實現,但哪一條是最佳方案卻難以確定。為了解決這一問題,有必要對SQL實施優化。簡單地說,SQL語句的優化就是將性能低下的SQL語句轉換成達到同樣目的的性能更好的SQL語句。

優化SQL語句的原因

資料庫系統的生命周期可以分成: 設計、開發和成品三個階段。在設計階段進行優化的成本最低,收益最大。在成品階段進行優化的成本最高,收益最小。如果將一個資料庫系統比喻成一座樓房,在樓房建好後進行矯正往往成本很高而收效很小(甚至可能根本無法矯正),而在樓房設計、生產階段控制好每塊磚瓦的質量就能達到花費小而見效高的目的。

為了獲得最大效益,人們常需要對資料庫進行優化。資料庫的優化通常可以通過對網路、硬體、操作系統、資料庫參數和應用程序的優化來進行。根據統計,對網路、硬體、操作系統、資料庫參數進行優化所獲得的性能提升全部加起來只佔資料庫應用系統性能提升的40%左右,其餘60%的系統性能提升全部來自對應用程序的優化。許多優化專家甚至認為對應用程序的優化可以得到80%的系統性能提升。因此可以肯定,通過優化應用程序來對資料庫系統進行優化能獲得更大的收益。

對應用程序的優化通常可分為兩個方面: 源代碼的優化和SQL語句的優化。由於涉及到對程序邏輯的改變,源代碼的優化在時間成本和風險上代價很高(尤其是對正在使用中的系統進行優化) 。另一方面,源代碼的優化對資料庫系統性能的提升收效有限,因為應用程序對資料庫的操作最終要表現為SQL語句對資料庫的操作。

對SQL語句進行優化有以下一些直接原因:

1. SQL語句是對資料庫(數據) 進行操作的惟一途徑,應用程序的執行最終要歸結為SQL語句的執行,SQL語句的效率對資料庫系統的性能起到了決定性的作用。

2. SQL語句消耗了70%~90%的資料庫資源。

3. SQL語句獨立於程序設計邏輯,對SQL語句進行優化不會影響程序邏輯,相對於對程序源代碼的優化,對SQL語句的優化在時間成本和風險上的代價都很低。

E. 如何在 SQL 資料庫優化 索引,SQL索引優化

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

F. 怎樣進行sql資料庫的優化

1、資料庫空間是個概述,在sqlserver里,使用語句 exec sp_spaceused 'TableName' 這個語句來查。

G. SQL資料庫如何優化

化總結如下:
1、主鍵就是聚集索引
2、只要建立索引就能顯著提高查詢速度
3、把所有需要提高查詢速度的欄位都加進聚集索引,以提高查詢速度
注意事項
1. 不要索引常用的小型表
2. 不要把社會保障號碼(SSN)或身份證號碼(ID)選作鍵
3. 不要用用戶的鍵
4. 不要索引 memo/notes 欄位和不要索引大型文本欄位(許多字元)
5. 使用系統生成的主鍵

H. 誰知道資料庫優化設計方案有哪些

本文首先討論了基於第三範式的資料庫表的基本設計,著重論述了建立主鍵和索引的策略和方案,然後從資料庫表的擴展設計和庫表對象的放置等角度概述了資料庫管理系統的優化方案。
關鍵詞: 優化(Optimizing) 第三範式(3NF) 冗餘數據(Rendant Data) 索引(Index) 數據分割(Data Partitioning) 對象放置(Object Placement)
1 引言
資料庫優化的目標無非是避免磁碟I/O瓶頸、減少CPU利用率和減少資源競爭。為了便於讀者閱讀和理解,筆者參閱了Sybase、Informix和Oracle等大型資料庫系統參考資料,基於多年的工程實踐經驗,從基本表設計、擴展設計和資料庫表對象放置等角度進行討論,著重討論了如何避免磁碟I/O瓶頸和減少資源競爭,相信讀者會一目瞭然。
2 基於第三範式的基本表設計
在基於表驅動的信息管理系統(MIS)中,基本表的設計規范是第三範式(3NF)。第三範式的基本特徵是非主鍵屬性只依賴於主鍵屬性。基於第三範式的資料庫表設計具有很多優點:一是消除了冗餘數據,節省了磁碟存儲空間;二是有良好的數據完整性限制,即基於主外鍵的參照完整限制和基於主鍵的實體完整性限制,這使得數據容易維護,也容易移植和更新;三是數據的可逆性好,在做連接(Join)查詢或者合並表時不遺漏、也不重復;四是因消除了冗餘數據(冗餘列),在查詢(Select)時每個數據頁存的數據行就多,這樣就有效地減少了邏輯I/O,每個Cash存的頁面就多,也減少物理I/O;五是對大多數事務(Transaction)而言,運行性能好;六是物理設計(Physical Design)的機動性較大,能滿足日益增長的用戶需求。
在基本表設計中,表的主鍵、外鍵、索引設計佔有非常重要的地位,但系統設計人員往往只注重於滿足用戶要求,而沒有從系統優化的高度來認識和重視它們。實際上,它們與系統的運行性能密切相關。現在從系統資料庫優化角度討論這些基本概念及其重要意義:
(1)主鍵(Primary Key):主鍵被用於復雜的SQL語句時,頻繁地在數據訪問中被用到。一個表只有一個主鍵。主鍵應該有固定值(不能為Null或預設值,要有相對穩定性),不含代碼信息,易訪問。把常用(眾所周知)的列作為主鍵才有意義。短主鍵最佳(小於25bytes),主鍵的長短影響索引的大小,索引的大小影響索引頁的大小,從而影響磁碟I/O。主鍵分為自然主鍵和人為主鍵。自然主鍵由實體的屬性構成,自然主鍵可以是復合性的,在形成復合主鍵時,主鍵列不能太多,復合主鍵使得Join*作復雜化、也增加了外鍵表的大小。人為主鍵是,在沒有合適的自然屬性鍵、或自然屬性復雜或靈敏度高時,人為形成的。人為主鍵一般是整型值(滿足最小化要求),沒有實際意義,也略微增加了表的大小;但減少了把它作為外鍵的表的大小。
(2)外鍵(Foreign Key):外鍵的作用是建立關系型資料庫中表之間的關系(參照完整性),主鍵只能從獨立的實體遷移到非獨立的實體,成為後者的一個屬性,被稱為外鍵。
(3)索引(Index):利用索引優化系統性能是顯而易見的,對所有常用於查詢中的Where子句的列和所有用於排序的列創建索引,可以避免整表掃描或訪問,在不改變表的物理結構的情況下,直接訪問特定的數據列,這樣減少數據存取時間;利用索引可以優化或排除耗時的分類*作;把數據分散到不同的頁面上,就分散了插入的數據;主鍵自動建立了唯一索引,因此唯一索引也能確保數據的唯一性(即實體完整性);索引碼越小,定位就越直接;新建的索引效能最好,因此定期更新索引非常必要。索引也有代價:有空間開銷,建立它也要花費時間,在進行Insert、Delete和Update*作時,也有維護代價。索引有兩種:聚族索引和非聚族索引。一個表只能有一個聚族索引,可有多個非聚族索引。使用聚族索引查詢數據要比使用非聚族索引快。在建索引前,應利用資料庫系統函數估算索引的大小。
① 聚族索引(Clustered Index):聚族索引的數據頁按物理有序儲存,佔用空間小。選擇策略是,被用於Where子句的列:包括范圍查詢、模糊查詢或高度重復的列(連續磁碟掃描);被用於連接Join*作的列;被用於Order by和Group by子句的列。聚族索引不利於插入*作,另外沒有必要用主鍵建聚族索引。
② 非聚族索引(Nonclustered Index):與聚族索引相比,佔用空間大,而且效率低。選擇策略是,被用於Where子句的列:包括范圍查詢、模糊查詢(在沒有聚族索引時)、主鍵或外鍵列、點(指針類)或小范圍(返回的結果域小於整表數據的20%)查詢;被用於連接Join*作的列、主鍵列(范圍查詢);被用於Order by和Group by子句的列;需要被覆蓋的列。對只讀表建多個非聚族索引有利。索引也有其弊端,一是創建索引要耗費時間,二是索引要佔有大量磁碟空間,三是增加了維護代價(在修改帶索引的數據列時索引會減緩修改速度)。那麼,在哪種情況下不建索引呢?對於小表(數據小於5頁)、小到中表(不直接訪問單行數據或結果集不用排序)、單值域(返回值密集)、索引列值太長(大於20bitys)、容易變化的列、高度重復的列、Null值列,對沒有被用於Where子語句和Join查詢的列都不能建索引。另外,對主要用於數據錄入的,盡可能少建索引。當然,也要防止建立無效索引,當Where語句中多於5個條件時,維護索引的開銷大於索引的效益,這時,建立臨時表存儲有關數據更有效。
批量導入數據時的注意事項:在實際應用中,大批量的計算(如電信話單計費)用C語言程序做,這種基於主外鍵關系數據計算而得的批量數據(文本文件),可利用系統的自身功能函數(如Sybase的BCP命令)快速批量導入,在導入資料庫表時,可先刪除相應庫表的索引,這有利於加快導入速度,減少導入時間。在導入後再重建索引以便優化查詢。
(4)鎖:鎖是並行處理的重要機制,能保持數據並發的一致性,即按事務進行處理;系統利用鎖,保證數據完整性。因此,我們避免不了死鎖,但在設計時可以充分考慮如何避免長事務,減少排它鎖時間,減少在事務中與用戶的交互,杜絕讓用戶控制事務的長短;要避免批量數據同時執行,尤其是耗時並用到相同的數據表。鎖的徵用:一個表同時只能有一個排它鎖,一個用戶用時,其它用戶在等待。若用戶數增加,則Server的性能下降,出現「假死」現象。如何避免死鎖呢?從頁級鎖到行級鎖,減少了鎖徵用;給小表增加無效記錄,從頁級鎖到行級鎖沒有影響,若在同一頁內競爭有影響,可選擇合適的聚族索引把數據分配到不同的頁面;創建冗餘表;保持事務簡短;同一批處理應該沒有網路交互。
(5)查詢優化規則:在訪問資料庫表的數據(Access Data)時,要盡可能避免排序(Sort)、連接(Join)和相關子查詢*作。經驗告訴我們,在優化查詢時,必須做到:
① 盡可能少的行;
② 避免排序或為盡可能少的行排序,若要做大量數據排序,最好將相關數據放在臨時表中*作;用簡單的鍵(列)排序,如整型或短字元串排序;
③ 避免表內的相關子查詢;
④ 避免在Where子句中使用復雜的表達式或非起始的子字元串、用長字元串連接;
⑤ 在Where子句中多使用「與」(And)連接,少使用「或」(Or)連接;
⑥ 利用臨時資料庫。在查詢多表、有多個連接、查詢復雜、數據要過濾時,可以建臨時表(索引)以減少I/O。但缺點是增加了空間開銷。
除非每個列都有索引支持,否則在有連接的查詢時分別找出兩個動態索引,放在工作表中重新排序。
3 基本表擴展設計
基於第三範式設計的庫表雖然有其優越性(見本文第一部分),然而在實際應用中有時不利於系統運行性能的優化:如需要部分數據時而要掃描整表,許多過程同時競爭同一數據,反復用相同行計算相同的結果,過程從多表獲取數據時引發大量的連接*作,當數據來源於多表時的連接*作;這都消耗了磁碟I/O和CPU時間。
尤其在遇到下列情形時,我們要對基本表進行擴展設計:許多過程要頻繁訪問一個表、子集數據訪問、重復計算和冗餘數據,有時用戶要求一些過程優先或低的響應時間。
如何避免這些不利因素呢?根據訪問的頻繁程度對相關表進行分割處理、存儲冗餘數據、存儲衍生列、合並相關表處理,這些都是克服這些不利因素和優化系統運行的有效途徑。
3.1 分割表或儲存冗餘數據
分割表分為水平分割表和垂直分割表兩種。分割表增加了維護數據完整性的代價。
水平分割表:一種是當多個過程頻繁訪問數據表的不同行時,水平分割表,並消除新表中的冗餘數據列;若個別過程要訪問整個數據,則要用連接*作,這也無妨分割表;典型案例是電信話單按月分割存放。另一種是當主要過程要重復訪問部分行時,最好將被重復訪問的這些行單獨形成子集表(冗餘儲存),這在不考慮磁碟空間開銷時顯得十分重要;但在分割表以後,增加了維護難度,要用觸發器立即更新、或存儲過程或應用代碼批量更新,這也會增加額外的磁碟I/O開銷。
垂直分割表(不破壞第三範式),一種是當多個過程頻繁訪問表的不同列時,可將表垂直分成幾個表,減少磁碟I/O(每行的數據列少,每頁存的數據行就多,相應佔用的頁就少),更新時不必考慮鎖,沒有冗餘數據。缺點是要在插入或刪除數據時要考慮數據的完整性,用存儲過程維護。另一種是當主要過程反復訪問部分列時,最好將這部分被頻繁訪問的列數據單獨存為一個子集表(冗餘儲存),這在不考慮磁碟空間開銷時顯得十分重要;但這增加了重疊列的維護難度,要用觸發器立即更新、或存儲過程或應用代碼批量更新,這也會增加額外的磁碟I/O開銷。垂直分割表可以達到最大化利用Cache的目的。
總之,為主要過程分割表的方法適用於:各個過程需要表的不聯結的子集,各個過程需要表的子集,訪問頻率高的主要過程不需要整表。在主要的、頻繁訪問的主表需要表的子集而其它主要頻繁訪問的過程需要整表時則產生冗餘子集表。
注意,在分割表以後,要考慮重新建立索引。
3.2 存儲衍生數據
對一些要做大量重復性計算的過程而言,若重復計算過程得到的結果相同(源列數據穩定,因此計算結果也不變),或計算牽扯多行數據需額外的磁碟I/O開銷,或計算復雜需要大量的CPU時間,就考慮存儲計算結果(冗餘儲存)。現予以分類說明:
若在一行內重復計算,就在表內增加列存儲結果。但若參與計算的列被更新時,必須要用觸發器更新這個新列。
若對表按類進行重復計算,就增加新表(一般而言,存放類和結果兩列就可以了)存儲相關結果。但若參與計算的列被更新時,就必須要用觸發器立即更新、或存儲過程或應用代碼批量更新這個新表。
若對多行進行重復性計算(如排名次),就在表內增加列存儲結果。但若參與計算的列被更新時,必須要用觸發器或存儲過程更新這個新列。
總之,存儲冗餘數據有利於加快訪問速度;但違反了第三範式,這會增加維護數據完整性的代價,必須用觸發器立即更新、或存儲過程或應用代碼批量更新,以維護數據的完整性。
3.3 消除昂貴結合
對於頻繁同時訪問多表的一些主要過程,考慮在主表內存儲冗餘數據,即存儲冗餘列或衍生列(它不依賴於主鍵),但破壞了第三範式,也增加了維護難度。在源表的相關列發生變化時,必須要用觸發器或存儲過程更新這個冗餘列。當主要過程總同時訪問兩個表時可以合並表,這樣可以減少磁碟I/O*作,但破壞了第三範式,也增加了維護難度。對父子表和1:1關系表合並方法不同:合並父子表後,產生冗餘表;合並1:1關系表後,在表內產生冗餘數據。
4 資料庫對象的放置策略
資料庫對象的放置策略是均勻地把數據分布在系統的磁碟中,平衡I/O訪問,避免I/O瓶頸。
⑴ 訪問分散到不同的磁碟,即使用戶數據盡可能跨越多個設備,多個I/O運轉,避免I/O競爭,克服訪問瓶頸;分別放置隨機訪問和連續訪問數據。
⑵ 分離系統資料庫I/O和應用資料庫I/O。把系統審計表和臨時庫表放在不忙的磁碟上。
⑶ 把事務日誌放在單獨的磁碟上,減少磁碟I/O開銷,這還有利於在障礙後恢復,提高了系統的安全性。
⑷ 把頻繁訪問的「活性」表放在不同的磁碟上;把頻繁用的表、頻繁做Join*作的表分別放在單獨的磁碟上,甚至把把頻繁訪問的表的欄位放在不同的磁碟上,把訪問分散到不同的磁碟上,避免I/O爭奪;
⑸ 利用段分離頻繁訪問的表及其索引(非聚族的)、分離文本和圖像數據。段的目的是平衡I/O,避免瓶頸,增加吞吐量,實現並行掃描,提高並發度,最大化磁碟的吞吐量。利用邏輯段功能,分別放置「活性」表及其非聚族索引以平衡I/O。當然最好利用系統的默認段。另外,利用段可以使備份和恢復數據更加靈活,使系統授權更加靈活。

I. 如何進行SQL性能優化

這里分享下mysql優化的幾種方法。

1、首先在打開的軟體中,需要分別為每一個表創建 InnoDB FILE的文件。

J. 關於SQL資料庫優化

具體要注意的:
1.應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0
2.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。優化器將無法通過索引來確定將要命中的行數,因此需要搜索該表的所有行。
3.應盡量避免在 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=20
4.in 和 not in 也要慎用,因為IN會使系統無法使用索引,而只能直接搜索表中的數據。如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
5.盡量避免在索引過的字元數據中,使用非打頭字母搜索。這也使得引擎無法利用索引。
見如下例子:
SELECT * FROM T1 WHERE NAME LIKE 『%L%』
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=』L』
SELECT * FROM T1 WHERE NAME LIKE 『L%』
即使NAME欄位建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數據逐條操作來完成任務。而第三個查詢能夠使用索引來加快操作。
6.必要時強制查詢優化器使用某個索引,如在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num
7.應盡量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
SELECT * FROM T1 WHERE F1/2=100
應改為:
SELECT * FROM T1 WHERE F1=100*2
SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=』5378』
應改為:
SELECT * FROM RECORD WHERE CARD_NO LIKE 『5378%』
SELECT member_number, first_name, last_name FROM members
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21
應改為:
SELECT member_number, first_name, last_name FROM members
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())
即:任何對列的操作都將導致表掃描,它包括資料庫函數、計算表達式等等,查詢時要盡可能將操作移至等號右邊。
8.應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--『2005-11-30』生成的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
9.不要在 where 子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
10.在使用索引欄位作為條件時,如果該索引是復合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應盡可能的讓欄位順序與索引順序相一致。
11.很多時候用 exists是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select top 1 from b where num=a.num)
SELECT SUM(T1.C1)FROM T1 WHERE(
(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)
SELECT SUM(T1.C1) FROM T1WHERE EXISTS(
SELECT * FROM T2 WHERE T2.C2=T1.C2)
兩者產生相同的結果,但是後者的效率顯然要高於前者。因為後者不會產生大量鎖定的表掃描或是索引掃描。
如果你想校驗表裡是否存在某條紀錄,不要用count(*)那樣效率很低,而且浪費伺服器資源。可以用EXISTS代替。如:
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')
可以寫成:
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')
經常需要寫一個T_SQL語句比較一個父結果集和子結果集,從而找到是否存在在父結果集中有而在子結果集中沒有的記錄,如:
SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表示tbl用別名a代替
WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)
SELECT a.hdr_key FROM hdr_tbl a
LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL
SELECT hdr_key FROM hdr_tbl
WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl)
三種寫法都可以得到同樣正確的結果,但是效率依次降低。
12.盡量使用表變數來代替臨時表。如果表變數包含大量數據,請注意索引非常有限(只有主鍵索引)。
13.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
14.臨時表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件,最好使用導出表。
15.在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。
16.如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

17.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。
18.盡量避免大事務操作,提高系統並發能力。
19.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

20. 避免使用不兼容的數據類型。例如float和int、char和varchar、binary和varbinary是不兼容的。數據類型的不兼容可能使優化器無法執行一些本來可以進行的優化操作。例如:
SELECT name FROM employee WHERE salary > 60000
在這條語句中,如salary欄位是money型的,則優化器很難對其進行優化,因為60000是個整型數。我們應當在編程時將整型轉化成為錢幣型,而不要等到運行時轉化。
21.充分利用連接條件,在某種情況下,兩個表之間可能不只一個的連接條件,這時在 WHERE 子句中將連接條件完整的寫上,有可能大大提高查詢速度。
例:
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO
第二句將比第一句執行快得多。
22、使用視圖加速查詢
把表的一個子集進行排序並創建視圖,有時能加速查詢。它有助於避免多重排序 操作,而且在其他方面還能簡化優化器的工作。例如:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.postcode>「98000」
ORDER BY cust.name
如果這個查詢要被執行多次而不止一次,可以把所有未付款的客戶找出來放在一個視圖中,並按客戶的名字進行排序:
CREATE VIEW DBO.V_CUST_RCVLBES
AS
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY cust.name
然後以下面的方式在視圖中查詢:
SELECT * FROM V_CUST_RCVLBES
WHERE postcode>「98000」
視圖中的行要比主表中的行少,而且物理順序就是所要求的順序,減少了磁碟I/O,所以查詢工作量可以得到大幅減少。
23、能用DISTINCT的就不用GROUP BY
SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID
可改為:
SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10
24.能用UNION ALL就不要用UNION
UNION ALL不執行SELECT DISTINCT函數,這樣就會減少很多不必要的資源

35.盡量不要用SELECT INTO語句。
SELECT INOT 語句會導致表鎖定,阻止其他用戶訪問該表。
上面我們提到的是一些基本的提高查詢速度的注意事項,但是在更多的情況下,往往需要反復試驗比較不同的語句以得到最佳方案。最好的方法當然是測試,看實現相同功能的SQL語句哪個執行時間最少,但是資料庫中如果數據量很少,是比較不出來的,這時可以用查看執行計劃,即:把實現相同功能的多條SQL語句考到查詢分析器,按CTRL+L看查所利用的索引,表掃描次數(這兩個對性能影響最大),總體上看詢成本百分比即可。

今天在itput上看了一篇文章,是討論一個語句的優化:
原貼地址: http://www.itpub.net/viewthread.php?tid=1015964&extra=&page=1
一,發現問題 優化的語句:
請問以下語句如何優化:
CREATE TABLE aa_001
( ip VARCHAR2(28),
name VARCHAR2(10),
password VARCHAR2(30) )

select * from aa_001 where ip in (1,2,3) order by name desc;
--目前表中記錄有一千多萬條左右,而且in中的值個數是不確定的。
以上就是優化的需要優化的語句和情況。

不少人在後面跟帖:有的說沒辦法優化,有的說將IN該為EXISTS,有的說在ip上建立索引復合索引(ip,name)等等。
二,提出問題 那這樣的情況,能優化嗎,如何優化?今天就來討論這個問題。
三,分析問題 1,數據量1千萬多條。
2,in中的值個數是不確定
3.1 分析數據分布 這里作者沒有提到ip列的數據的分布情況,目前ip列的數據分布可能有以下幾種:
1,ip列(數據唯一,或者數據重復的概率很小)
2,ip列 (數據不均勻,可能有些數據重復多,有些重復少)
3,ip列 (數據分布比較均勻,數據大量重復,主要就是一些同樣的數據(可能只有上萬級別不同的ip數據等)

解決問題:
1,對於第一種數據分布情況,只要在ip列建立一個索引即可。這時不管表有多少行, in個數是不確定的情況下,都很快。
2,對應第二中數據分布情況,在ip列建立索引,效果不好。因為數據分布不均勻,可能有些快,有些慢
3,對應第三種數據分布情況,在ip列建立索引,速度肯定慢。
注意:這里的 order by name desc 是在取出數據後再排序的。而不是取數據前排序

對於2,3兩個情況,因為都是可能需要取出大量的數據,優化器就採用表掃描(table scan),而不是索引查找(index seek) ,速度很慢,因為這時表掃描效率要優於索引查找,特別是高並發情況下,效率很低。

那對應2,3中情況,如何處理。是將in改成exists。其實在sql server 2005和oracle里的優化器在in後面數據少時,效率是一樣的。這時採用一般的索引效率很低。這時如果在ip列上建立聚集索引,效率會比較高。我們在SQL server 2005中做個測試。

表:[dbo].[[zping.com]]]中有約200萬條數據。包含列Userid, id, Ruleid等列。按照上面的情況查詢一下類似語句:
select * from [dbo].[[zping.com]]] where
userid in ('',''
,'') order by Ruleid desc

我們先看userid的數據分布情況,執行下面語句:
select userid,count(*) from [dbo].[[zping.com]]] group by userid order by 2
這時我們看看數據分布:總共有379條數據,數據兩從1到15萬都有,數據分布傾斜嚴重。下圖是其中一部分。

這時如果在ip上建立非聚集索引,效率很低,而且就是強行索引掃描,效率也很低,會發現IO次數比表掃描還高。這時只能在ip上建立聚集索引。這時看看結果。

這時發現,搜索採用了(clustered index seek)聚集搜索掃描。
在看看查詢返回的結果:
(156603 行受影響)
表 '[zping.com]'。掃描計數 8,邏輯讀取 5877 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。
表 'Worktable'。掃描計數 0,邏輯讀取 0 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。
返回15萬行,才不到6千次IO。效率較高,因為這15萬行要排序,查詢成本里排序佔了51%。當然可以建立(userid,Ruleid)復合聚集索引,提高性能,但這樣做DML維護成本較高。建議不採用。

從上面的測試例子可以看出, 優化的解決辦法:
數據分布為1:建立ip索引即可
數據分布為2,3:在ip列建立聚集索引。