数据库性能优化手法

1.创建必要的索引 (在经常检索的字段进行创建索引,比如以图书名称来进行检索,就需要在这个图书名称的字段创建索引)
2.使用预编译查询(程序中通常是根据用户的输入来动态执行 SQL 语句,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞攻击,最重要数据库会对这些参数化 SQL执行预编译,这样第一次执行的时候 DBMS会为这个SQL 语句进行查询优化并且执行预编译,这样以后再执行这个 SQL 的时候就直接使用预编译的结果,这样可以大大提高执行的速度。)
3.调整 WHERE 子句中的连接顺序
DBMS 一般采用自下而上的顺序解析 WHERE 子句,根据这个原理,表连接最好写
在其他 WHERE条件之前,那些可以过滤掉最大数量记录。
比如下面的 SQL语句性能较差:
SELECT *
FROM T_Person
WHERE FSalary > 50000
AND FPosition= ‘MANAGER’
AND 25 < (SELECT COUNT(*) FROM T_Manager
WHERE FManagerId=2);
我们将子查询的条件放到最前面,下面的 SQL语句性能比较好:
SELECT *
FROM T_Person
WHERE
25 < (SELECT COUNT(*) FROM T_Manager
WHERE FManagerId=2)
AND FSalary > 50000
AND FPosition= ‘MANAGER’ ;
4.SELECT语句中避免使用'*'
 
5.尽量将多条 SQL语句压缩到一句SQL
6.Where子句替换 HAVING 子句
避免使用 HAVING 子句,因为HAVING 只会在检索出所有记录之后才对结果集
进行过滤。如果能通过 WHERE 子句限制记录的数目,那就能减少这方面的开销。
HAVING 中的条件一般用于聚合函数的过滤,除此而外,应该将条件写在 WHERE
句中
7. 使用表的别名
当在 SQL 语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这
样就可以减少解析的时间并减少那些由列名歧义引起的语法错误。
8.EXISTS替代 IN
在查询中,为了满足一个条件,往往需要对另一个表进行联接,在这种情况下,使
EXISTS而不是 IN 通常将提高查询的效率,因为 IN 子句将执行一个子查询内部的排
序和合并。下面的语句 2 就比语句1 效率更加高。
语句 1
SELECT * FROM T_Employee
WHERE FNumber> 0
AND FDEPTNO IN (SELECT FNumber
FROM T_Department
WHERE FMangerName = 'Tome')
语句 2SELECT * FROM T_Employee
WHERE FNumber > 0
AND EXISTS (SELECT 1
FROM T_Department
WHERE T_Department. FDEPTNO = EMP.FNumber
AND FMangerName = ‘MELB’ )
9.用表连接替换 EXISTS
通常来说,表连接的方式比 EXISTS 更有效率,因此如果可能的话尽量使用表连
接替换 EXISTS。下面的语句2 就比语句 1 效率更加高。
语句 1
SELECT FName FROM T_Employee
WHERE EXISTS
(
SELECT 1 FROM T_Department
WHERE T_Employee.FDepartNo= FNumber
AND FKind='A'
);
语句 2SELECT FName FROM T_Department, T_Employee
WHERE T_Employee. FDepartNo = T_Departmen. FNumber
AND FKind = ‘A ’ ;
10.避免在索引列上使用计算
WHERE 子句中,如果索引列是计算或者函数的一部分, DBMS 的优化器将不
会使用索引而使用全表扫描。
例如下面的 SQL语句用于检索月薪的12倍大于两万五千元的员工:
SELECT *FROM T_Employee
WHERE FSalary * 12 >25000;
由于在大于号左边的是 FSalary12 的成绩表达式,这样 DBMS 的优化器将不会
使用字段 FSalary的索引,因为DBMS必须对 T_Employee表进行全表扫描,从而计算
FSalary * 12 的值,然后与25000 进行比较。将上面的 SQL语句修改为下面的等价写法
DBMS将会使用索引查找,从而大大提高了效率:
SELECT *FROM T_Employee
WHERE FSalary >25000/12;
同样的,不能在索引列上使用函数,因为函数也是一种计算,会造成全表扫描。下
面的语句 2就比语句1 效率更加高。
语句 1
SELECT * FROM T_Example
WHERE ABS(FAmount)=300
语句 2SELECT * FROM T_Example
WHERE FAmount=300 OR FAmount=-300
11.UNION ALL 替换 UNION
SQL 语句需要 UNION 两个查询结果集合时,即使检索结果中不会有重复的记
录,如果使用 UNION这两个结果集同样会尝试进行合并,然后在输出最终结果前进行
排序。
因此,如果检索结果中不会有重复的记录的话,应该用 UNION ALL替代UNION ,这
样效率就会因此得到提高。下面的语句 2 就比语句1 效率更加高。
语句 1
SELECTACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS1
WHERE TRAN_DATE = '20010101'
UNION
SELECTACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS2
WHERE TRAN_DATE ='20010102'
语句 2
SELECTACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS1
WHERE TRAN_DATE ='20010101'
UNION ALL
SELECTACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS2
WHERE TRAN_DATE = '20010102'
12.避免隐式类型转换造成的全表扫描
T_Person 表的字符串类型字段FLevel 为人员的级别,在 FAge 字段上建有索引。
我们执行下面的 SQL语句用于检索所有级别等于 10的员工:
SELECT FId,FAge,FName
FROM T_Person
WHERE FAge=10
在这个 SQL 语句中,将字符串类型字段 FLevel 与数值10 进行比较,由于在大部
分数据库中隐式转换类型中数值类型的优先级高于字符串类型,因此 DBMS会对FAge
字段进行隐式类型转换,相当于执行了下面的 SQL语句:
SELECT FId,FAge,FName
FROM T_Person
WHERE TO_INT(FAge)=10
由于在索引字段上进行了计算,所以造成了索引失效而使用全表扫描。因此应将
SQL语句做如下修改:
SELECT FId,FAge,FName
FROM T_Person
WHERE FAge='10'
13.防止检索范围过宽
如果 DBMS 优化器认为检索范围过宽,那么它将放弃索引查找而使用全表扫描。
下面是几种可能造成检索范围过宽的情况:
使用 IS NOT NULL或者不等于判断,可能造成优化器假设匹配的记录数太多。
使用 LIKE 运算符的时候,"a%"将会使用索引,而 "a%c""%c" 则会使用全表扫描,因
"a%c" "%c"不能被有效的评估匹配的数量。
14.事务
如果要执行一系列的操作,而这些操作最终是以整体的原子操作的形式完成的话,
事务就是必须的。关于事务的理论中,银行转账问题是最经典的例子:当把钱从一个银
行帐号转移至另外一个银行帐号的时候,这个操作要由两个步骤来完成,首先要将资金
从一个银行帐号取出,然后再将其存入另一个银行帐号。如果资金已经从一个银行帐号
取出了,在将资金存入另一个银行帐号之前或者进行当中发生异常情况 (包括程序内部
异常、服务器当机、目标帐号被冻结 ),如果没有事务保护就会出现源帐号中的资金已
经减少了,但是目标帐号中的资金并没有增加的状况。
事务是关键业务系统开发中非常关键性的服务,对于关键性业务系统如果没有采用事
务,那么这个系统可以说是不可用的。
posted @ 2015-09-17 16:52  许大虾  阅读(212)  评论(0编辑  收藏  举报