SQL优化

SQL优化

创建必要的索引
使用预编译查询

程序中通常是根据用户的输入来动态的执行SQL语句,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞攻击,最重要数据库会对这些参数化SQL执行预编译,这样第一次执行的时候DBMS会为这个SQL语句进行查询优化并且执行预编译,这样以后再执行这个SQL的时候就直接使用预编译的结果,这样可以大大提高执行速
度。

调整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’; 
SELECT 语句中避免使用’*’
尽量将多条SQL语句压缩到一句SQL中

每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程使非常耗时的,因此应该尽量避免过多的执行SQL语句,能够压缩到一句SQL执行的语句就不要用多条来执行。

用where子句替换HAVING子句

避免使用HAVING 子句,因为HAVING 只会在检索出所有记录进行过滤。如果能通过 WHERE 子句限制记录的数目,那就能减少这方面的开销。 HAVING 中的条件一般用于聚合函数的过滤,除此而外,应该将条件写在WHERE 子 句中。

使用表的别名

当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于某个列上。这样就可以减少解析的时间并减少那些由列明歧义引起的语法错误。

用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') 
-- 语句2: 
SELECT * FROM T_Employee 
WHERE FNumber > 0 
AND EXISTS (SELECT 1 
FROM T_Department 
WHERE T_Department. FDEPTNO = EMP.FNumber 
AND FMangerName = ‘MELB’) 
用表连接替换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' 
); 
-- 语句2: 
SELECT FName FROM T_Department, T_Employee 
WHERE T_Employee. FDepartNo = T_Departmen. FNumber 
AND FKind = ‘A’; 
避免在索引列上使用计算

在WHERE 子句中,如果索引列是计算或者函数的一部分,DBMS 的优化器将不 会使用索引而使用全表扫描。
例如下面的SQL 语句用于检索月薪的12 倍大于两万五千元的员工:
SELECT *FROM T_Employee
WHERE FSalary * 12 >25000;
由于在大于号左边的是FSalary 与12 的成绩表达式,这样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 
-- 语句2: 
SELECT * FROM T_Example 
WHERE FAmount=300 OR FAmount=-300 
用UNION ALL替换UNION

当SQL语句需要UNIONl两个查询结果集合时,即时检索结果中不会有重复的记录,如果使用UNION这两个结果集同样会尝试进行合并,然后在输出最终结果前进行排序。
因此,如果检索结果中不会有重复的记录的话,应该用UNION ALL 替代UNION,这样效率就会因此得到提高。
下面的语句2 就比语句1 效率更加高。

语句1:
SELECT ACCT_NUM, BALANCE_AMT 
FROM DEBIT_TRANSACTIONS1 
WHERE TRAN_DATE = '20010101' 
UNION 
SELECT ACCT_NUM, BALANCE_AMT 
FROM DEBIT_TRANSACTIONS2 
WHERE TRAN_DATE ='20010102' 
语句2: 
SELECT ACCT_NUM, BALANCE_AMT 
FROM DEBIT_TRANSACTIONS1 
WHERE TRAN_DATE ='20010101' 
UNION ALL 
SELECT ACCT_NUM, BALANCE_AMT 
FROM DEBIT_TRANSACTIONS2 
WHERE TRAN_DATE = '20010102' 
避免隐式类型转换造成的全表扫描

详见以下:https://blog.youkuaiyun.com/markzy/article/details/80323454

防止检索范围过宽

如果DBMS优化器认为检索范围过宽,那么它将放弃索引查找而使用全表扫描。
几种可能造成检索范围过宽的情况:

  • 使用 IS NOT NULL或者不等于判断,可能造成优化器假设匹配的记录数太多;
  • 使用LIKE运算符的时候,“a%”将会使用索引,而“a%c”和“%c”则会使用全表扫描,因 此"a%c"和"%c"不能被有效的评估匹配的数量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值