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