① sql執行與優化
SQL優化
執行計劃,表關聯查詢順序,優化策略與思路
下面再向前走一些,容我根據自己的認識說一下查詢執行的流程是怎樣的:
1.連接
1.1客戶端發起一條Query請求,監聽客戶端的『連接管理模塊』接收請求
1.2將請求轉發到『連接進/線程模塊』
1.3調用『用戶模塊』來進行授權檢查
1.4通過檢查後,『連接進/線程模塊』從『線程連接池』中取出空閑的被緩存的連接線程和客戶端請求對接,如果失敗則創建一個新的連接請求
2.處理
2.1先查詢緩存,檢查Query語句是否完全匹配,接著再檢查是否具有許可權,都成功則直接取數據返回
2.2上一步有失敗則轉交給『命令解析器』,經過詞法分析,語法分析後生成解析樹
2.3接下來是預處理階段,處理解析器無法解決的語義,檢查許可權等,生成新的解析樹
2.4再轉交給對應的模塊處理
2.5如果是SELECT查詢還會經由『查詢優化器』做大量的優化,生成執行計劃
2.6模塊收到請求後,通過『訪問控制模塊』檢查所連接的用戶是否有訪問目標表和目標欄位的許可權
2.7有則調用『表管理模塊』,先是查看table cache中是否存在,有則直接對應的表和獲取鎖,否則重新打開表文件
2.8根據表的meta數據,獲取表的存儲引擎類型等信息,通過介面調用對應的存儲引擎處理
2.9上述過程中產生數據變化的時候,若打開日誌功能,則會記錄到相應二進制日誌文件中
3.結果
3.1Query請求完成後,將結果集返回給『連接進/線程模塊』
3.2返回的也可以是相應的狀態標識,如成功或失敗等
3.3『連接進/線程模塊』進行後續的清理工作,並繼續等待請求或斷開與客戶端的連接
接下來再走一步,讓我們看看一條SQL語句的前世今生。
首先看一下示例語句
示例語句
執行順序
SQL解析
1. FROM
當涉及多個表的時候,左邊表的輸出會作為右邊表的輸入,之後會生成一個虛擬表VT1。
(1-J1)笛卡爾積
計算兩個相關聯表的笛卡爾積(CROSS JOIN) ,生成虛擬表VT1-J1。
兩次全表掃描
哈希索引,查找復雜度都是 O(1) 。
2. WHERE
對VT1過程中生成的臨時表進行過濾,滿足WHERE子句的列被插入到VT2表中。
注意:
此時因為分組,不能使用聚合運算;也不能使用SELECT中創建的別名;
與ON的區別:
如果有外部列,ON針對過濾的是關聯表,主表(保留表)會返回所有的列;
如果沒有添加外部列,兩者的效果是一樣的;
應用:
對主表的過濾應該放在WHERE;
對於關聯表,先條件查詢後連接則用ON,先連接後條件查詢則用WHERE;
hash join 哈希連接 驅動表和被驅動表都只會訪問0次或1次
應用場景:一個大表一個小表/表上沒有索引/返回結果集比較大
3. GROUP BY
這個子句會把VT2中生成的表按照GROUP BY中的列進行分組。生成VT3表。
注意:
其後處理過程的語句,如SELECT,HAVING,所用到的列必須包含在GROUP BY中,對於沒有出現的,得用聚合函數;
原因:
GROUP BY改變了對表的引用,將其轉換為新的引用方式,能夠對其進行下一級邏輯操作的列會減少;
原作者的理解是:
根據分組欄位,將具有相同分組欄位的記錄歸並成一條記錄,因為每一個分組只能返回一條記錄,除非是被過濾掉了,而不在分組欄位裡面的欄位可能會有多個值,多個值是無法放進一條記錄的,所以必須通過聚合函數將這些具有多值的列轉換成單值;
GROUP BY 重新聚合查詢
4. HAVING
這個子句對VT3表中的不同的組進行過濾,只作用於分組後的數據,滿足HAVING條件的子句被加入到VT4表中。
7.LIMIT
LIMIT子句從上一步得到的VT6虛擬表中選出從指定位置開始的指定行數據。
注意:
offset和rows的正負帶來的影響;
當偏移量很大時效率是很低的,可以這么做:
採用子查詢的方式優化,在子查詢里先從索引獲取到最大id,然後倒序排,再取N行結果集
採用INNER JOIN優化,JOIN子句里也優先從索引獲取ID列表,然後直接關聯查詢獲得最終結果
當前未用到索引,
三次full scan , table1 AS a / table2 AS b / GROUP BY
盡量少做重復的工作
控制同一語句的多次執/減少多次的數據轉換/
杜絕不必要的子查詢和連接表,子查詢在執行計劃一般解釋成外連接,多餘的連接表帶來額外的開銷
關於臨時表和表變數的選擇
臨時表產生使用SELECT INTO和CREATE TABLE + INSERT INTO的選擇,一般情況下,SELECT INTO會比CREATE TABLE + INSERT INTO的方法快很多,但是SELECT INTO會鎖定TEMPDB的系統表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用戶並發環境下,容易阻塞其他進程,所以建議,在並發系統中,盡量使用CREATE TABLE + INSERT INTO,而大數據量的單個語句使用中,使用SELECT INTO。
子查詢的用法
相關子查詢可以用IN、NOT IN、EXISTS、NOT EXISTS引入
NOT IN、NOT EXISTS的相關子查詢可以改用LEFT JOIN代替寫法
如果保證子查詢沒有重復 ,IN、EXISTS的相關子查詢可以用INNER JOIN 代替
IN``的相關子查詢用EXISTS代替
不要用 COUNT (*)的子查詢判斷是否存在記錄,最好用 LEFT` `JOIN 或者EXISTS,比如有人寫這樣的語句:
建立索引後,並不是每個查詢都會使用索引,在使用索引的情況下,索引的使用效率也會有很大的差別。只要我們在查詢語句中沒有強制指定索引,
不要對索引欄位進行運算,而要想辦法做變換
不要對索引欄位進行格式轉換
不要對索引欄位使用函數
不要對索引欄位進行多欄位連接
join關聯查詢的計算是很復雜的,特別是數據量比較大的情況下,實際情況還是拆解較快的
Join拆解的核心就是利用In關鍵字
要麼用空間換時間,要麼用時間換空間
多表連接的連接條件對索引的選擇有著重要的意義,所以我們在寫連接條件條件的時候需要特別注意。
A、多表連接的時候,連接條件必須寫全,寧可重復,不要缺漏。
B、連接條件盡量使用聚集索引
C、注意ON、WHERE和HAVING部分條件的區別
ON是最先執行, WHERE次之,HAVING最後,因為ON是先把不符合條件的記錄過濾後才進行統計,它就可以減少中間運算要處理的數據,按理說應該速度是最快的,WHERE也應該比 HAVING快點的,因為它過濾數據後才進行SUM,在兩個表聯接時才用ON的,所以在一個表的時候,就剩下WHERE跟HAVING比較了
考慮聯接優先順序:
(1)INNER JOIN
(2)LEFT JOIN (註:RIGHT JOIN 用 LEFT JOIN 替代)
(3)CROSS JOIN
索引並不適用於所有情況:a.少量數據;b.頻繁進行改動的欄位,不適合做索引;c.很少使用的欄位,不需要加索引
索引會提高數據查詢效率,但是會降低「增、刪、改」的效率。當不使用索引的時候,我們進行數據的增刪改,只需要操作源表即可,但是當我們添加索引後,不僅需要修改源表,也需要再次修改索引,很麻煩。
先執行順序, 是否走索引, 有無類型轉換
18000 字的SQL優化大全
步步深入:MySQL架構總覽->查詢執行流程->SQL解析順序
MySQL索引總結(4)——btree與hash區別
② 如何監控一句SQL執行的效率用什麼工具如何監控
用sqlServer自帶的sql server profiler
可以監視sql執行的cpu佔用率,執行時長等
③ SQL進行優化
改成如下試一試
SELECT
B.ORG_ID,
B.ORG_NAME,
SUM(A.CUR_BAL_SUM) AS TOTAL_BAL FROM
( SELECT OPEN_ACCT_ORG_ID,CUR_BAL_SUM FORM ECRVIEW.BAC_ACCT_BAL_SUM A
WHERE A.DATA_DT =DATE '2012-05-23') A INNER JOIN PVIEW.T04_ORG B
ON A.OPEN_ACCT_ORG_ID=B.ORG_ID GROUP BY 1.2;
④ 如何進行SQL性能優化
這里分享下mysql優化的幾種方法。
1、首先在打開的軟體中,需要分別為每一個表創建 InnoDB FILE的文件。
⑤ sql語句性能如何優化
如何加快查詢速度?
1、升級硬體
2、根據查詢條件,建立索引,優化索引、優化訪問方式,限制結果集的數據量。
3、擴大伺服器的內存
4、增加伺服器CPU個數
5、對於大的資料庫不要設置資料庫自動增長,它會降低伺服器的性能
6、在查詢Select語句中用Where字句限制返回的行數,避免表掃描,如果返回不必要的數據,浪費了伺服器的I/O資源,加重了網路的負擔降低性能。如果表很大,在表掃描的期間將表鎖住,禁止其他的聯接訪問表,後果嚴重。
7、查詢時不要返回不需要的行、列
8、用select top 100 / 10 Percent 來限制用戶返回的行數或者SET ROWCOUNT來限制操作的行
9、在IN後面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最後面,減少判斷的次數
10、一般在GROUP BY 個HAVING字句之前就能剔除多餘的行,所以盡量不要用它們來做剔除行的工作。他們的執行順序應該如下最優:
select的Where字句選擇所有合適的行,Group By用來分組個統計行,Having字句用來剔除多餘的分組。這樣Group By 個Having的開銷小,查詢快.對於大的數據行進行分組和Having十分消耗資源。如果Group BY的目的不包括計算,只是分組,那麼用Distinct更快
11、一次更新多條記錄比分多次更新每次一條快,就是說批處理好
⑥ 什麼是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 復合索引:如果在兩上以上的列上創建的索引,則稱為復合索引。
⑦ 請簡述項目中優化sql語句執行效率的方法,從哪些方面,sql語句性能如何分析
1. SQL優化的原則是:將一次操作需要讀取的BLOCK數減到最低,即在最短的時間達到最大的數據吞吐量。
調整不良SQL通常可以從以下幾點切入:
? 檢查不良的SQL,考慮其寫法是否還有可優化內容
? 檢查子查詢 考慮SQL子查詢是否可以用簡單連接的方式進行重新書寫
? 檢查優化索引的使用
? 考慮資料庫的優化器
2. 避免出現SELECT * FROM table 語句,要明確查出的欄位。
3. 在一個SQL語句中,如果一個where條件過濾的資料庫記錄越多,定位越准確,則該where條件越應該前移。
4. 查詢時盡可能使用索引覆蓋。即對SELECT的欄位建立復合索引,這樣查詢時只進行索引掃描,不讀取數據塊。
5. 在判斷有無符合條件的記錄時建議不要用SELECT COUNT (*)和select top 1 語句。
6. 使用內層限定原則,在拼寫SQL語句時,將查詢條件分解、分類,並盡量在SQL語句的最里層進行限定,以減少數據的處理量。
7. 應絕對避免在order by子句中使用表達式。
8. 如果需要從關聯表讀數據,關聯的表一般不要超過7個。
9. 小心使用 IN 和 OR,需要注意In集合中的數據量。建議集合中的數據不超過200個。
10. <> 用 < 、 > 代替,>用>=代替,<用<=代替,這樣可以有效的利用索引。
11. 在查詢時盡量減少對多餘數據的讀取包括多餘的列與多餘的行。
12. 對於復合索引要注意,例如在建立復合索引時列的順序是F1,F2,F3,則在where或order by子句中這些欄位出現的順序要與建立索引時的欄位順序一致,且必須包含第一列。只能是F1或F1,F2或F1,F2,F3。否則不會用到該索引。
13. 多表關聯查詢時,寫法必須遵循以下原則,這樣做有利於建立索引,提高查詢效率。格式如下select sum(table1.je) from table1 table1, table2 table2, table3 table3 where (table1的等值條件(=)) and (table1的非等值條件) and (table2與table1的關聯條件) and (table2的等值條件) and (table2的非等值條件) and (table3與table2的關聯條件) and (table3的等值條件) and (table3的非等值條件)。
注:關於多表查詢時from 後面表的出現順序對效率的影響還有待研究。
14. 子查詢問題。對於能用連接方式或者視圖方式實現的功能,不要用子查詢。例如:select name from customer where customer_id in ( select customer_id from order where money>1000)。應該用如下語句代替:select name from customer inner join order on customer.customer_id=order.customer_id where order.money>100。
15. 在WHERE 子句中,避免對列的四則運算,特別是where 條件的左邊,嚴禁使用運算與函數對列進行處理。比如有些地方 substring 可以用like代替。
16. 如果在語句中有not in(in)操作,應考慮用not exists(exists)來重寫,最好的辦法是使用外連接實現。
17. 對一個業務過程的處理,應該使事物的開始與結束之間的時間間隔越短越好,原則上做到資料庫的讀操作在前面完成,資料庫寫操作在後面完成,避免交叉。
18. 請小心不要對過多的列使用列函數和order by,group by等,謹慎使用disti軟體開發t。
19. 用union all 代替 union,資料庫執行union操作,首先先分別執行union兩端的查詢,將其放在臨時表中,然後在對其進行排序,過濾重復的記錄。
當已知的業務邏輯決定query A和query B中不會有重復記錄時,應該用union all代替union,以提高查詢效率。
⑧ 怎樣進行sql資料庫的優化
1、資料庫空間是個概述,在sqlserver里,使用語句 exec sp_spaceused 'TableName' 這個語句來查。
⑨ 如何進行SQL性能優化
這里分享下mysql優化的幾種方法。
1、首先在打開的軟體中,需要分別為每一個表創建 InnoDB FILE的文件。
⑩ 如何進行SQL性能優化
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樹存放。