sqlserver和mysql性能优化_SQLSERVERSQL性能优化
1.选择最有效率的表名顺序(只在基于规则的优化器中有效)
SQLSERVER的解析器按照从右到左的顺序处理FROM⼦句中的表名,因此FROM⼦句中写在最后的表(基础表driving table)将被最先处理,在FROM⼦句中包含多个表的情况下,必须选择记录条数最少的表作为基础表,当SQLSERVER处理多个表时,会运⽤排序及合并的⽅式连接它们,
⾸先,扫描第⼀个表(FROM⼦句中最后的那个表)并对记录进⾏排序;然后扫描第⼆个表(FROM⼦句中最后第⼆个表);最后将所有从第⼆个表中检索出的记录与第⼀个表中合适记录进⾏合并
例如: 表 TAB1 16,384 条记录表 TAB2 5 条记录,选择TAB2作为基础表 (最好的⽅法) select count(*) from tab1,tab2 执⾏时间0.96秒,选择TAB2作为基础表 (不佳的⽅法) select count(*) from tab2,tab1 执⾏时间26.09秒;
如果有3个以上的表连接查询,那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引⽤的表
例如:
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⼦句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最⼤数量记录的条件必须写在WHERE⼦句的末尾
例如:
(低效,执⾏时间156.3秒)
SELECT *
FROM EMP E
WHERE SAL > 50000
AND JOB = ’MANAGER’
AND 25
(⾼效,执⾏时间10.6秒)
SELECT *
FROM EMP E
WHERE 25
AND SAL > 50000
AND JOB = ’MANAGER’;
3.SELECT⼦句中避免使⽤’*’。当你想在SELECT⼦句中列出所有的COLUMN时,使⽤动态SQL列引⽤’*’是⼀个⽅便的⽅法,不幸的是,这是⼀个⾮常低效的⽅法。实际上,SQLSERVER在解析的过程中,会将’*’依次转换成所有的列名,这个⼯作是通过查询数据字典完成的,这意味着将耗费更多的时间
4.减少访问数据库的次数。当执⾏每条SQL语句时,SQLSERVER在内部执⾏了许多⼯作:解析SQL语句,估算索引的利⽤率,绑定变量,读数据块等等
由此可见,减少访问数据库的次数,就能实际上减少SQLSERVER的⼯作量,例如:
以下有三种⽅法可以检索出雇员号等于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);
sql优化的几种方式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函数来减少处理时间
使⽤DECODE函数可以避免重复扫描相同记录或重复连接相同的表
例如:
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函数⾼效地得到相同结果
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’表⽰任何⼀个字段
类似的,DECODE函数也可以运⽤于GROUP BY和ORDER BY⼦句中
6.⽤Where⼦句替换HAVING⼦句
避免使⽤HAVING⼦句,HAVING只会在检索出所有记录之后才对结果集进⾏过滤,这个处理需要排序、统计等操作如果能通过WHERE⼦句限制记录的数⽬,那就能减少这⽅⾯的开销
例如:
低效
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.减少对表的查询
在含有⼦查询的SQL语句中,要特别注意减少对表的查询
例如:
低效
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多个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),当在SQL语句中连接多个表时,请使⽤表的别名并把别名前缀于每个Column上,这样可以减少解析的时间并减少那些由Column歧义引起的语法错误
9.⽤EXISTS替代IN
在许多基于基础表的查询中,为了满⾜⼀个条件,往往需要对另⼀个表进⾏联接
在这种情况下,使⽤EXISTS(或NOT EXISTS)通常将提⾼查询的效率
低效
SELECT *
FROM EMP (基础表)
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC = ’MELB’)
⾼效
SELECT *
FROM EMP (基础表)
WHERE EMPNO > 0
AND EXISTS (SELECT ’X’
FROM DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ’MELB’)
10.⽤NOT EXISTS替代NOT IN
在⼦查询中,NOT IN⼦句将执⾏⼀个内部的排序和合并
⽆论在哪种情况下,NOT IN都是最低效的,因为它对⼦查询中的表执⾏了⼀个全表遍历
为了避免使⽤NOT IN,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS
例如:
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。