专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »数据库 » sql语句:SQL语句性能调整原则 »正文

sql语句:SQL语句性能调整原则

来源: 发布时间:星期二, 2009年2月3日 浏览:73次 评论:0
="t18">、问题提出
在应用系统开发初期由于开发数据库数据比较少对于查询SQL语句复杂视图编写等体会不出SQL语句各种写法性能优劣但是如果将应用系统提交实际应用后随着数据库中数据增加系统响应速度就成为目前系统需要解决最主要问题的系统优化中个很重要方面就是SQL语句优化对于海量数据劣质SQL语句和优质SQL语句的间速度差别可以达到上百倍可见对于个系统不是简单地能实现其功能就可而是要写出高质量SQL语句提高系统可用性

在多数情况下Oracle使用索引来更快地遍历表优化器主要根据定义索引来提高性能但是如果在SQL语句where子句中写SQL代码不合理就会造成优化器删去索引而使用全表扫描般就这种SQL语句就是所谓劣质SQL语句在编写SQL语句时我们应清楚优化器根据何种原则来删除索引这有助于写出高性能SQL语句

2、SQL语句编写注意问题
下面就某些SQL语句where子句编写中需要注意问题作详细介绍在这些where子句中即使某些列存在索引但是由于编写了劣质SQL系统在运行该SQL语句时也不能使用该索引而同样使用全表扫描这就造成了响应速度极大降低

1. IS NULL 和 IS NOT NULL
不能用null作索引任何包含null值列都将不会被包含在索引中即使索引有多列这样情况下只要这些列中有列含有null该列就会从索引中排除也就是说如果某列存在空值即使对该列建索引也不会提高性能

任何在where子句中使用is null或is not null语句优化器是不允许使用索引

2. 联接列

对于有联接即使最后联接值为个静态值优化器是不会使用索引我们起来看个例子假定有个职工表(employee)对于个职工姓和名分成两列存放(FIRST_NAME和LAST_NAME)现在要查询个叫比尔.克林顿(Bill Cliton)职工

下面是个采用联接查询SQL语句

select * from employss
where
first_name||''||last_name ='Beill Cliton';

上面这条语句完全可以查询出是否有Bill Cliton这个员工但是这里需要注意系统优化器对基于last_name创建索引没有使用

当采用下面这种SQL语句编写Oracle系统就可以采用基于last_name创建索引

Select * from employee
where
first_name ='Beill' and last_name ='Cliton';

遇到下面这种情况又如何处理呢?如果个变量(name)中存放着Bill Cliton这个员工姓名对于这种情况我们又如何避免全程遍历使用索引呢?可以使用将变量name中姓和名分开就可以了但是有点需要注意这个是不能作用在索引列上下面是SQL查询脚本:

select * from employee
where
first_name = SUBSTR('&&name',1,INSTR('&&name',' ')-1)
and
last_name = SUBSTR('&&name',INSTR('&&name’,' ')+1)

3. 带通配符(%)like语句

同样以上面例子来看这种情况目前需求是这样要求在职工表中查询名字中包含cliton可以采用如下查询SQL语句:

select * from employee where last_name like '%cliton%';

这里由于通配符(%)在搜寻词首出现所以Oracle系统不使用last_name索引在很多情况下可能无法避免这种情况但是定要心中有底通配符如此使用会降低查询速度然而当通配符出现在串其他位置时优化器就能利用索引在下面查询中索引得到了使用:

select * from employee where last_name like 'c%';

4. Order by语句

ORDER BY语句决定了Oracle如何将返回查询结果排序Order by语句对要排序列没有什么特别限制也可以将加入列中(象联接或者附加等)任何在Order by语句非索引项或者有计算表达式都将降低查询速度

仔细检查order by语句以找出非索引项或者表达式它们会降低性能解决这个问题办法就是重写order by语句以使用索引也可以为所使用列建立另外个索引同时应绝对避免在order by子句中使用表达式

5. NOT

我们在查询时经常在where子句使用些逻辑表达式如大于、小于、等于以及不等于等等也可以使用and(和)、or(或)以及not(非)NOT可用来对任何逻辑运算符号取反下面是个NOT子句例子:

... where not (status ='VALID')

如果要使用NOT则应在取反短语前面加上括号并在短语前面加上NOT运算符NOT运算符包含在另外个逻辑运算符中这就是不等于(<>)运算符换句话说即使不在查询where子句中显式地加入NOT词NOT仍在运算符中见下例:

... where status <>'INVALID';

再看下面这个例子:

select * from employee wheresalary<>3000;

对这个查询可以改写为不使用NOT:

select * from employee wheresalary<3000 or salary>3000;

虽然这两种查询结果但是第 2种查询方案会比第种查询方案更快些第 2种查询允许Oracle对salary列使用索引而第种查询则不能使用索引

6.IN和EXISTS

有时候会将列和系列值相比较最简单办法就是在where子句中使用子查询在where子句中可以使用两种格式子查询

种格式是使用IN操作符:

... where column in(select * from ... where ...);

第 2种格式是使用EXIST操作符:

... where exists (select 'X' from ...where ...);

我相信绝大多数人会使用第种格式它比较容易编写而实际上第 2种格式要远比第种格式效率高在Oracle中可以几乎将所有IN操作符子查询改写为使用EXISTS子查询

第 2种格式中子查询以‘select 'X'开始运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用列存在索引)相对于IN子句来说EXISTS使用相连子查询构造起来要比IN子查询困难

通过使用EXISTOracle系统会首先检查主查询然后运行子查询直到它找到第个匹配项这就节省了时间Oracle系统在执行IN子查询时首先执行子查询并将获得结果列表存放在在个加了索引临时表中在执行子查询的前系统先将主查询挂起待子查询执行完毕存放在临时表中以后再执行主查询这也就是使用EXISTS比使用IN通常查询速度快原因

同时应尽可能使用NOT EXISTS来代替NOT IN尽管 2者都使用了NOT(不能使用索引而降低速度)NOT EXISTS要比NOT IN查询效率更高
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: