日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql sqlserver 性能优化_SQLSERVER SQL性能优化技巧

發(fā)布時(shí)間:2025/4/17 数据库 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql sqlserver 性能优化_SQLSERVER SQL性能优化技巧 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.選擇最有效率的表名順序(只在基于規(guī)則的優(yōu)化器中有效)

SQLSERVER的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最后的表(基礎(chǔ)表driving table)將被最先處理,在FROM子句中包含多個(gè)表的情況下,必須選擇記錄條數(shù)最少的表作為基礎(chǔ)表,當(dāng)SQLSERVER處理多個(gè)表時(shí),會(huì)運(yùn)用排序及合并的方式連接它們,

首先,掃描第一個(gè)表(FROM子句中最后的那個(gè)表)并對(duì)記錄進(jìn)行排序;然后掃描第二個(gè)表(FROM子句中最后第二個(gè)表);最后將所有從第二個(gè)表中檢索出的記錄與第一個(gè)表中合適記錄進(jìn)行合并

例如: 表 TAB1 16,384 條記錄表 TAB2 5 條記錄,選擇TAB2作為基礎(chǔ)表 (最好的方法) select count(*) from tab1,tab2 執(zhí)行時(shí)間0.96秒,選擇TAB2作為基礎(chǔ)表 (不佳的方法) select count(*) from tab2,tab1 執(zhí)行時(shí)間26.09秒;

如果有3個(gè)以上的表連接查詢,那就需要選擇交叉表(intersection table)作為基礎(chǔ)表,交叉表是指那個(gè)被其他表所引用的表

例如:

EMP表描述了LOCATION表和CATEGORY表的交集

SELECT *

FROM LOCATION L,

CATEGORY C,

EMP E

WHERE E.EMP_NO BETWEEN 1000 AND 2000

AND E.CAT_NO = C.CAT_NO

AND E.LOCN = L.LOCN

將比下列SQL更有效率

SELECT *

FROM EMP E ,

LOCATION L ,

CATEGORY C

WHERE E.CAT_NO = C.CAT_NO

AND E.LOCN = L.LOCN

AND E.EMP_NO BETWEEN 1000 AND 2000

2.WHERE子句中的連接順序

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

例如:

(低效,執(zhí)行時(shí)間156.3秒)

SELECT *

FROM EMP E

WHERE SAL > 50000

AND JOB = 'MANAGER'

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

(高效,執(zhí)行時(shí)間10.6秒)

SELECT *

FROM EMP E

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

AND SAL > 50000

AND JOB = 'MANAGER';

3.SELECT子句中避免使用'*'。當(dāng)你想在SELECT子句中列出所有的COLUMN時(shí),使用動(dòng)態(tài)SQL列引用'*'是一個(gè)方便的方法,不幸的是,這是一個(gè)非常低效的方法。實(shí)際上,SQLSERVER在解析的過程中,會(huì)將'*'依次轉(zhuǎn)換成所有的列名,這個(gè)工作是通過查詢數(shù)據(jù)字典完成的,這意味著將耗費(fèi)更多的時(shí)間

4.減少訪問數(shù)據(jù)庫的次數(shù)。當(dāng)執(zhí)行每條SQL語句時(shí),SQLSERVER在內(nèi)部執(zhí)行了許多工作:解析SQL語句,估算索引的利用率,綁定變量,讀數(shù)據(jù)塊等等

由此可見,減少訪問數(shù)據(jù)庫的次數(shù),就能實(shí)際上減少SQLSERVER的工作量,例如:

以下有三種方法可以檢索出雇員號(hào)等于0342或0291的職員

方法1 (最低效)

SELECT EMP_NAME, SALARY, GRADE

FROM EMP

WHERE EMP_NO = 342;

SELECT EMP_NAME, SALARY, GRADE

FROM EMP

WHERE EMP_NO = 291;

方法2 (次低效)

DECLARE

CURSOR C1 (E_NO NUMBER) IS

SELECT EMP_NAME,SALARY,GRADE

FROM EMP

WHERE EMP_NO = E_NO;

BEGIN

OPEN C1(342);

FETCH C1 INTO …,…,…;

OPEN C1(291);

FETCH C1 INTO …,…,…;

CLOSE C1;

END;

方法2 (高效)

SELECT A.EMP_NAME, A.SALARY, A.GRADE,

B.EMP_NAME, B.SALARY, B.GRADE

FROM EMP A, EMP B

WHERE A.EMP_NO = 342

AND B.EMP_NO = 291;

5.使用DECODE函數(shù)來減少處理時(shí)間

使用DECODE函數(shù)可以避免重復(fù)掃描相同記錄或重復(fù)連接相同的表

例如:

SELECT COUNT(*), SUM(SAL)

FROM EMP

WHERE DEPT_NO = '0020'

AND ENAME LIKE 'SMITH%';

SELECT COUNT(*), SUM(SAL)

FROM EMP

WHERE DEPT_NO = '0030'

AND ENAME LIKE 'SMITH%';

你可以用DECODE函數(shù)高效地得到相同結(jié)果

SELECT COUNT(DECODE(DEPT_NO, '0020', 'X', NULL)) D0020_COUNT,

COUNT(DECODE(DEPT_NO, '0030', 'X', NULL)) D0030_COUNT,

SUM(DECODE(DEPT_NO, '0020', SAL, NULL)) D0020_SAL,

SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL

FROM EMP

WHERE ENAME LIKE 'SMITH%';

'X'表示任何一個(gè)字段

類似的,DECODE函數(shù)也可以運(yùn)用于GROUP BY和ORDER BY子句中

6.用Where子句替換HAVING子句

避免使用HAVING子句,HAVING只會(huì)在檢索出所有記錄之后才對(duì)結(jié)果集進(jìn)行過濾,這個(gè)處理需要排序、統(tǒng)計(jì)等操作

如果能通過WHERE子句限制記錄的數(shù)目,那就能減少這方面的開銷

例如:

低效

SELECT REGION, AVG(LOG_SIZE)

FROM LOCATION

GROUP BY REGION

HAVING REGION REGION != 'SYDNEY'

AND REGION != 'PERTH'

高效

SELECT REGION, AVG(LOG_SIZE)

FROM LOCATION

WHERE REGION REGION != 'SYDNEY'

AND REGION != 'PERTH'

GROUP BY REGION

7.減少對(duì)表的查詢

在含有子查詢的SQL語句中,要特別注意減少對(duì)表的查詢

例如:

低效

SELECT TAB_NAME

FROM TABLES

WHERE TAB_NAME = (SELECT TAB_NAME

FROM TAB_COLUMNS

WHERE VERSION = 604)

AND DB_VER = (SELECT DB_VER

FROM TAB_COLUMNS

WHERE VERSION = 604)

高效

SELECT TAB_NAME

FROM TABLES

WHERE (TAB_NAME, DB_VER) = (SELECT TAB_NAME, DB_VER

FROM TAB_COLUMNS

WHERE VERSION = 604)

Update多個(gè)Column例子:

低效

UPDATE EMP

SET EMP_CAT = (SELECT MAX(CATEGORY)

FROM EMP_CATEGORIES),

SAL_RANGE = (SELECT MAX(SAL_RANGE)

FROM EMP_CATEGORIES)

WHERE EMP_DEPT = 0020;

高效

UPDATE EMP

SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY), MAX(SAL_RANGE)

FROM EMP_CATEGORIES)

WHERE EMP_DEPT = 0020;

8.使用表的別名(Alias),當(dāng)在SQL語句中連接多個(gè)表時(shí),請(qǐng)使用表的別名并把別名前綴于每個(gè)Column上,這樣可以減少解析的時(shí)間并減少那些由Column歧義引起的語法錯(cuò)誤

9.用EXISTS替代IN

在許多基于基礎(chǔ)表的查詢中,為了滿足一個(gè)條件,往往需要對(duì)另一個(gè)表進(jìn)行聯(lián)接

在這種情況下,使用EXISTS(或NOT EXISTS)通常將提高查詢的效率

低效

SELECT *

FROM EMP (基礎(chǔ)表)

WHERE EMPNO > 0

AND DEPTNO IN (SELECT DEPTNO

FROM DEPT

WHERE LOC = 'MELB')

高效

SELECT *

FROM EMP (基礎(chǔ)表)

WHERE EMPNO > 0

AND EXISTS (SELECT 'X'

FROM DEPT

WHERE DEPT.DEPTNO = EMP.DEPTNO

AND LOC = 'MELB')

10.用NOT EXISTS替代NOT IN

在子查詢中,NOT IN子句將執(zhí)行一個(gè)內(nèi)部的排序和合并

無論在哪種情況下,NOT IN都是最低效的,因?yàn)樗鼘?duì)子查詢中的表執(zhí)行了一個(gè)全表遍歷

為了避免使用NOT IN,我們可以把它改寫成外連接(Outer Joins)或NOT EXISTS

例如:

SELECT …

FROM EMP

WHERE DEPT_NO NOT IN (SELECT DEPT_NO

FROM DEPT

WHERE DEPT_CAT = 'A');

為了提高效率改寫為

高效

SELECT …

FROM EMP A, DEPT B

WHERE A.DEPT_NO = B.DEPT(+)

AND B.DEPT_NO IS NULL

AND B.DEPT_CAT(+) = 'A'

最高效

SELECT …

FROM EMP E

WHERE NOT EXISTS (SELECT 'X'

FROM DEPT D

WHERE D.DEPT_NO = E.DEPT_NO

AND DEPT_CAT = 'A');

11.用表連接替換EXISTS

通常來說,采用表連接的方式比EXISTS更有效率

例如:

SELECT ENAME

FROM EMP E

WHERE EXISTS (SELECT 'X'

FROM DEPT

WHERE DEPT_NO = E.DEPT_NO

AND DEPT_CAT = 'A');

更高效

SELECT ENAME

FROM DEPT D, EMP E

WHERE E.DEPT_NO = D.DEPT_NO

AND DEPT_CAT = 'A';

12.用EXISTS替換DISTINCT

當(dāng)提交一個(gè)包含多表信息(比如部門表和雇員表)的查詢時(shí),避免在SELECT子句中使用DISTINCT,一般可以考慮用EXIST替換

例如:

低效

SELECT DISTINCT DEPT_NO, DEPT_NAME

FROM DEPT D, EMP E

WHERE D.DEPT_NO = E.DEPT_NO

高效

SELECT DEPT_NO, DEPT_NAME

FROM DEPT D

WHERE EXISTS (SELECT 'X'

FROM EMP E

WHERE E.DEPT_NO = D.DEPT_NO);

EXISTS使查詢更為迅速,因?yàn)镽DBMS核心模塊將在子查詢的條件一旦滿足后,立刻返回結(jié)果

13.用索引提高效率

索引是表的一個(gè)概念部分,用來提高檢索數(shù)據(jù)的效率。實(shí)際上,SQLSERVER使用了一個(gè)復(fù)雜的自平衡B-tree結(jié)構(gòu)

通常,通過索引查詢數(shù)據(jù)比全表掃描要快。當(dāng)SQLSERVER找出執(zhí)行查詢和Update語句的最佳路徑時(shí),SQLSERVER優(yōu)化器將使用索引

同樣,在聯(lián)結(jié)多個(gè)表時(shí)使用索引也可以提高效率。另一個(gè)使用索引的好處是,它提供了主鍵(primary key)的唯一性驗(yàn)證

除了那些LONG或LONG RAW數(shù)據(jù)類型,你可以索引幾乎所有的列

通常在大型表中使用索引特別有效,當(dāng)然,在掃描小表時(shí),使用索引同樣能提高效率

雖然使用索引能得到查詢效率的提高,但是我們也必須注意到它的代價(jià)

索引需要空間來存儲(chǔ),也需要定期維護(hù),每當(dāng)有記錄在表中增減或索引列被修改時(shí),索引本身也會(huì)被修改

這意味著每條記錄的INSERT、DELETE、UPDATE將為此多付出4、5次的磁盤I/O

因?yàn)樗饕枰~外的存儲(chǔ)空間和處理,那些不必要的索引反而會(huì)使查詢反應(yīng)時(shí)間變慢

SQLSERVER對(duì)索引有兩種訪問模式:

1).索引唯一掃描(INDEX UNIQUE SCAN)

大多數(shù)情況下, 優(yōu)化器通過WHERE子句訪問INDEX

例如:

表LODGING有兩個(gè)索引:建立在LODGING列上的唯一性索引LODGING_PK和建立在MANAGER列上的非唯一性索引LODGING$MANAGER

SELECT *

FROM LODGING

WHERE LODGING = 'ROSE HILL';

在內(nèi)部,上述SQL將被分成兩步執(zhí)行:

首先,LODGING_PK索引將通過索引唯一掃描的方式被訪問,獲得相對(duì)應(yīng)的ROWID;然后通過ROWID訪問表的方式執(zhí)行下一步檢索

如果被檢索返回的列包括在INDEX列中,SQLSERVER將不執(zhí)行第二步的處理(通過ROWID訪問表)

因?yàn)闄z索數(shù)據(jù)保存在索引中,單單訪問索引就可以完全滿足查詢結(jié)果

2).索引范圍查詢(INDEX RANGE SCAN)

適用于兩種情況:

1>.基于唯一性索引的一個(gè)范圍的檢索

2>.基于非唯一性索引的檢索

例1

SELECT LODGING

FROM LODGING

WHERE LODGING LIKE 'M%';

WHERE子句條件包括一系列值,SQLSERVER將通過索引范圍查詢的方式查詢LODGING_PK

由于索引范圍查詢將返回一組值,它的效率就要比索引唯一掃描低一些

例2

SELECT LODGING

FROM LODGING

WHERE MANAGER = 'BILL GATES';

這個(gè)SQL的執(zhí)行分兩步,LODGING$MANAGER的索引范圍查詢(得到所有符合條件記錄的ROWID),通過ROWID訪問表得到LODGING列的值

由于LODGING$MANAGER是一個(gè)非唯一性的索引,數(shù)據(jù)庫不能對(duì)它執(zhí)行索引唯一掃描

WHERE子句中,如果索引列所對(duì)應(yīng)的值的第一個(gè)字符由通配符(WILDCARD)開始,索引將不被采用

SELECT LODGING

FROM LODGING

WHERE MANAGER LIKE '%HANMAN';

在這種情況下,SQLSERVER將使用全表掃描

14.避免在索引列上使用計(jì)算

WHERE子句中,如果索引列是函數(shù)的一部分,優(yōu)化器將不使用索引而使用全表掃描

例如:

低效

SELECT …

FROM DEPT

WHERE SAL * 12 > 25000;

高效

SELECT …

FROM DEPT

WHERE SAL > 25000/12;

請(qǐng)務(wù)必注意,檢索中不要對(duì)索引列進(jìn)行處理,如:TRIM,TO_DATE,類型轉(zhuǎn)換等操作,破壞索引,使用全表掃描,影響SQL執(zhí)行效率

15.避免在索引列上使用IS NULL和IS NOT NULL

避免在索引中使用任何可以為空的列,SQLSERVER將無法使用該索引

對(duì)于單列索引,如果列包含空值,索引中將不存在此記錄;

對(duì)于復(fù)合索引,如果每個(gè)列都為空,索引中同樣不存在此記錄。如果至少有一個(gè)列不為空,則記錄存在于索引中

如果唯一性索引建立在表的A列和B列上,并且表中存在一條記錄的A,B值為(123,null),

SQLSERVER將不接受下一條具有相同A,B值(123,null)的記錄插入

如果所有的索引列都為空,SQLSERVER將認(rèn)為整個(gè)鍵值為空,而空不可能等于空,因此你可以插入1000條具有相同鍵值的記錄,當(dāng)然它們都是空!

因?yàn)榭罩挡淮嬖谟谒饕兄?#xff0c;所以WHERE子句中對(duì)索引列進(jìn)行空值比較將使SQLSERVER停用該索引

低效(索引失效)

SELECT …

FROM DEPARTMENT

WHERE DEPT_CODE IS NOT NULL

16.使用UNION-ALL和UNION

當(dāng)SQL語句需要UNION兩個(gè)查詢結(jié)果集合時(shí),這兩個(gè)結(jié)果集合會(huì)以UNION-ALL的方式被合并,然后在輸出最終結(jié)果前進(jìn)行排序

如果用UNION ALL替代UNION,這樣排序就不是必要了,效率就會(huì)因此得到提高

需要注意的是,UNION ALL將重復(fù)輸出兩個(gè)結(jié)果集合中相同記錄,因此還是要從業(yè)務(wù)需求分析使用UNION ALL的可行性

關(guān)于索引下列經(jīng)驗(yàn)請(qǐng)參考:

1).如果檢索數(shù)據(jù)量超過30%的表中記錄數(shù),使用索引將沒有顯著的效率提高

2).在特定情況下,使用索引也許會(huì)比全表掃描慢,但這是同一個(gè)數(shù)量級(jí)上的差距;而通常情況下,使用索引比全表掃描要快幾倍乃至幾千倍!

總結(jié)

以上是生活随笔為你收集整理的mysql sqlserver 性能优化_SQLSERVER SQL性能优化技巧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。