`

改写SQL语句优化MySQL性能

阅读更多

一、问题的提出 

在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一。系统优化中一个很重要的方面就是SQL语句的优化。对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的SQL语句,提高系统的可用性。 

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

二、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 where salary<>;3000; 

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

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

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

6. IN和EXISTS 

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

第一种格式是使用IN操作符: 

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

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

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

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

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

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

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

原文:http://www.leoyung.com/article/8012.htm

分享到:
评论

相关推荐

    MySQL是如何基于各种规则去优化执行计划的

    执行顺序:虽然SQL语句的编写顺序是固定的,但MySQL在执行时会按照不同的顺序处理各个子句,以优化性能2。 常量传播:如果查询中有多个条件可以通过常量替换简化,MySQL会进行这样的优化,例如将x=y AND y=k AND k=3...

    飙升:SQL Optimizer和Rewriter

    目前只支持MySQL语法族协议SQL优化 支持基于启发式算法的语句优化 支持复杂查询的多列索引优化(UPDATE,INSERT,DELETE,SELECT) 支持EXPLAIN信息丰富解读 支持SQL指纹,压缩和美化 支持同一张表多条ALTER请求合并...

    MYSQL培训经典教程(共两部分) 1/2

    数据库优化 177 8.1 索引的使用 178 8.1.1索引对单个表查询的影响 ...SQL语句 187 8.3.2 SELECT 查询的速度 188 8.3.2.1 MySQL怎样优化WHERE子句 188 8.3.2.2 MySQL怎样优化LEFT JOIN 190 8.3.2.3 ...

    优化mysql的limit offset的例子

    经常碰到的一个问题是limit的offset太高,如:limit 100000,20,这样系统会查询100020条,然后把前面的100000条都扔掉,这是开销很大的操作,导致查询很慢。...这条语句就可以优化为: 代码如下:select * from

    SQL开发几个实用规则

    SQL语句尽可能简单 保持事务(连接)短小 尽可能避免使用SP/TRIG/FUNC 尽量不用 SELECT * 改写OR语句 避免负向查询和% 前缀模糊查询 减少COUNT(*) LIMIT的高效分页 用UNION ALL 而非 UNION GROUP BY 去除排序 同数据...

    Python Scrapy爬虫爬取微博和微信公众号热门消息

    爬取微博需要以字典的形式设置自己的cookie。用于初学者学习,分别用了bf4和xpath,数据处理还不完善,存入了mysql数据库,改写sql语句就可以写入自己的表中

    MYSQL培训经典教程(共两部分) 2/2

    数据库优化 177 8.1 索引的使用 178 8.1.1索引对单个表查询的影响 ...SQL语句 187 8.3.2 SELECT 查询的速度 188 8.3.2.1 MySQL怎样优化WHERE子句 188 8.3.2.2 MySQL怎样优化LEFT JOIN 190 8.3.2.3 ...

    mldn BBS源码(经历自己改写,运行完全正常)

    哈哈,本人最近在CSDN上看了不少源码,但每次下载都要积分.本人积分少啊.取之于网络,也想还之于可爱的网络. share.这是个很不错的项目,大家若是运行起来,看能懂的话,是一件很惬意的事,水平能...sql语句也全在里边.mysql

    mysql笔记.txt

    sql语句改写 select customer_id,title,content from product_comment where audit_status=1 and product_id=199 limit 0,5; 该语句缺点越往后翻页效率越差, 适用于表数据量不大,10000行一下, 或者查询条件...

    支持多数据库的ORM框架ef-orm.zip

    EF-ORM中采用了独特的SQL解析和改写技术,能够主动检查并确保SQL语句或者SQL片段在各个数据库上的兼容性。 EF中除了Criteria API以外,可以直接使用“SQL语句”或者“SQL片段”。但是这些SQL语句并不是直接传送给...

    Db_mssql_class

    由于工作的原因,需要对SQL SERVER数据库进行操作,根据以前使用的MySQL数据库操作类改写成现在这个对SQL SERVER进行操作的PHP类,可以执行连接数据库,执行SQL语句,查询数据,获得最后一次插入操作的ID号等功能!

    Mysql limit 优化,百万至千万级快速分页 复合索引的引用并应用于轻量级框架

    MySql 这个数据库绝对是适合dba级的高手去玩的,一般做一点1万篇新闻的小型系统怎么写都可以,用xx框架可以实现快速开发。可是数据量到了10万,百万至千万,他的性能还能那么高吗?一点小小的失误,可能造成整个系统...

    mysql技巧:提高插入数据(添加记录)的速度

    2、改写所有insert语句为insert delayed 这个insert delayed不同之处在于:立即返回结果,后台进行处理插入。 还有一个技巧是在一跳insert中插入多条数据,类似insert into tablename values(‘xxx’,’xxx’),(...

    互联网金融公司在分布式数据库的运维实践

    1、业务上子查询SQL过多,需要大量改写为join关联查询语句,开发需要更改代码在MariaDB5.3版本里,就已经对子查询进行了优化,并采用semijoin半连接方式将SQL改写为了表关联join,从而提高了查询速度。通常情况下,...

    大数据之运维.pptx

    Hive简介 Hive 是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速...

    送强力打狗棒,文末领取

    手工测试sql语句的经验告诉我,所有fuzz过狗payload本质都是正则匹配逃逸(包括特殊的截断),正则匹配逃逸的核心要点绝不是/××/注释。于是对造轮子作者的payload进行测试,发现最终有用的是#a (安全狗4.0) 所以...

    MySQL死锁套路之唯一索引下批量插入顺序不一致

    为了方便演示,把批量插入改写为了多条 insert。 先来做几个小实验,简化的表结构如下 CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` varchar(5), `b` varchar(5), PRIMARY KEY (`id`), ...

    Hive用户指南(Hive_user_guide)_中文版.pdf

    3、 解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化以及 查询计划的生成。生成的查询计划存储在 HDFS 中,并在随后有 MapReduce 调用执行。 4、 Hive 的数据存储在 HDFS 中,大部分的...

Global site tag (gtag.js) - Google Analytics