MySQL查询优化系列讲座之查询优化器(1)

    当你提交一个查询的时候,MySQL会分析它,看是否可以做一些优化使处理该查询的速度更快。这一部分将介绍查询优化器是如何工作的。如果你想知道MySQL采用的优化手段,可以查看MySQL参考手册。

当然,MySQL查询优化器也利用了索引,但是它也使用了其它一些信息。例如,如果你提交如下所示的查询,那么无论数据表有多大,MySQL执行它的速度都会非常快:

SELECT * FROM tbl_name WHERE 0;

在这个例子中,MySQL查看WHERE子句,认识到没有符合查询条件的数据行,因此根本就不考虑搜索数据表。你可以通过提供一个EXPLAIN语句看到这种情况,这个语句让MySQL显示自己执行的但实际上没有真正地执行的SELECT查询的一些信息。如果要使用EXPLAIN,只需要在EXPLAIN单词放在SELECT语句的前面:

mysql> EXPLAIN SELECT * FROM tbl_name WHERE 0\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra: Impossible WHERE

通常情况下,EXPLAIN返回的信息比上面的信息要多一些,还包括用于扫描数据表的索引、使用的联结类型、每张数据表中估计需要检查的数据行数量等非空(NULL)信息。

优化器是如何工作的

MySQL查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行。你的最终目标是提交SELECT语句查找数据行,而不是排除数据行。优化器试图排除数据行的原因在于它排除数据行的速度越快,那么找到与条件匹配的数据行也就越快。如果能够首先进行最严格的测试,查询就可以执行地更快。假设你的查询检验了两个数据列,每个列上都有索引:

SELECT col3 FROM mytable
WHERE col1 = ’some value’ AND col2 = ’some other value’;

假设col1上的测试匹配了900个数据行,col2上的测试匹配了300个数据行,而同时进行的测试只得到了30个数据行。先测试Col1会有900个数据行,需要检查它们找到其中的30个与col2中的值匹配记录,其中就有870次是失败了。先测试col2会有300个数据行,需要检查它们找到其中的30个与col1中的值匹配的记录,只有270次是失败的,因此需要的计算和磁盘I/O更少。其结果是,优化器会先测试col2,因为这样做开销更小。

你可以通过下面一个指导帮助优化器更好地利用索引:

尽量比较数据类型相同的数据列。当你在比较操作中使用索引数据列的时候,请使用数据类型相同的列。相同的数据类型比不同类型的性能要高一些。例如,INT与BIGINT是不同的。CHAR(10)被认为是CHAR(10)或VARCHAR(10),但是与CHAR(12)或VARCHAR(12)不同。如果你所比较的数据列的类型不同,那么可以使用ALTER TABLE来修改其中一个,使它们的类型相匹配。

尽可能地让索引列在比较表达式中独立。如果你在函数调用或者更复杂的算术表达式条件中使用了某个数据列,MySQL就不会使用索引,因为它必须计算出每个数据行的表达式值。有时候这种情况无法避免,但是很多情况下你可以重新编写一个查询让索引列独立地出现。

下面的WHERE子句显示了这种情况。它们的功能相同,但是对于优化目标来说就有很大差异了:

WHERE mycol < 4 / 2
WHERE mycol * 2 < 4

对于第一行,优化器把表达式4/2简化为2,接着使用mycol上的索引来快速地查找小于2的值。对于第二个表达式,MySQL必须检索出每个数据行的mycol值,乘以2,接着把结果与4进行比较。在这种情况下,不会使用索引。数据列中的每个值都必须被检索到,这样才能计算出比较表达式左边的值。

我们看另外一个例子。假设你对date_col列进行了索引。如果你提交一条如下所示的查询,就不会使用这个索引:

SELECT * FROM mytbl WHERE YEAR(date_col) < 1990;

这个表达式不会把1990与索引列进行比较;它会把1990与该数据列计算出来的值比较,而每个数据行都必须计算出这个值。其结果是,没有使用date_col上的索引,因为执行这样的查询需要全表扫描。怎么解决这个问题呢?只需要使用文本日期,接着就可以使用date_col上的索引来查找列中匹配的值了:

WHERE date_col < ’1990-01-01’

但是,假设你没有特定的日期。你可能希望找到一些与今天相隔固定的几天的日期的记录。表达这种类型的比较有很多种方法--它们的效率并不同。下面就有三种:

WHERE TO_DAYS(date_col) - TO_DAYS(CURDATE()) < cutoff
WHERE TO_DAYS(date_col) < cutoff + TO_DAYS(CURDATE())
WHERE date_col < DATE_ADD(CURDATE(), INTERVAL cutoff DAY)

对于第一行,不会用到索引,因为每个数据行都必须检索以计算出TO_DAYS(date_col)的值。第二行要好一些。Cutoff和TO_DAYS(CURDATE())都是常量,因此在处理查询之前,比较表达式的右边可以被优化器一次性计算出来,而不需要每个数据行都计算一次。但是date_col列仍然出现在函数调用中,它阻止了索引的使用。第三行是这几个中最好的。同样,在执行查询之前,比较表达式的右边可以作为常量一次性计算出来,但是现在它的值是一个日期。这个值可以直接与date_col值进行比较,再也不需要转换成天数了。在这种情况下,会使用索引。

时间: 2024-07-30 10:10:37

MySQL查询优化系列讲座之查询优化器(1)的相关文章

MySQL查询优化系列讲座之查询优化器(2)

    为了使这个查询的效率更高,给其中一个联结列添加索引并重新执行EXPLAIN语句: mysql> ALTER TABLE t2 ADD INDEX (i2);mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: t1type

MySQL查询优化系列讲座之调度和锁定

    前面的部分主要是聚焦于如何让单独的查询执行的速度更快.MySQL还允许你改变语句调度的优先级,它可以使来自多个客户端的查询更好地协作,这样单个客户端就不会由于锁定而等待很长时间.改变优先级还可以确保特定类型的查询被处理得更快.这一部分讲解MySQL的默认的调度策略和可以用来影响这些策略的选项.它还谈到了并发性插入操作的使用和存储引擎锁定层次对客户端的并发性的影响.为了讨论的方便,我们把执行检索(SELECT)的客户端称为"读取者",把执行修改操作(DELETE.INSERT.R

MySQL查询优化系列讲座之数据类型与效率

    这一部分提供了如何选择数据类型来帮助提高查询运行速度的一些指导: 在可以使用短数据列的时候就不要用长的.如果你有一个固定长度的CHAR数据列,那么就不要让它的长度超出实际需要.如果你在数据列中存储的最长的值有40个字符,就不要定义成CHAR(255),而应该定义成CHAR(40).如果你能够用MEDIUMINT代替BIGINT,那么你的数据表就小一些(磁盘I/O少一些),在计算过程中,值的处理速度也快一些.如果数据列被索引了,那么使用较短的值带来的性能提高更加显著.不仅索引可以提高查询速

MySQL学习系列2--MySQL执行计划分析EXPLAIN

原文:MySQL学习系列2--MySQL执行计划分析EXPLAIN 1.Explain语法 EXPLAIN SELECT -- 变体:   EXPLAIN EXTENDED SELECT -- 将执行计划"反编译"成SELECT语句,运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句   2.执行计划分析和实例 创建员工表Employee create table Employee ( ID int auto_increment, Ename varchar(32

资深网站运营总监“莫言”的网站运营系列讲座(一)

网站运营 主讲:莫言主题:网站运营系列讲座(一) 讲课记录: 运营一个网站,咱们还是先从自身资源开始谈 自身资源里,包括了人员,资金,你的站所处领域里你对业务的熟悉程度 当然也包括一些硬件资源 类似服务器,或者空间 带宽 这些都是需要你前期考虑好的,并辅助与实施的 这里,要着重提的是你做站一定要选自己熟悉的行业领域 引一句话"不要拿自己的弱项跟人家的强项拼" 选择自己熟悉,或者说正在从事的领域行业来做站这是首选的 还包括你领域里可以整合其他的小范围领域 这些..可以统称为"网

Mysql入门系列:客户机程序5—MYSQL交互式查询程序

6.7 客户机程序5-交互式查询程序 让我们把迄今为止研究的诸多内容整理一下,编写一个简单的交互式客户机程序.它的功能包括可以进入查询,用通用目标查询处理程序process_query 执行查询,并用前面研究过的显示格式process_result_set() 显示查询结果. 客户机程序5在某些方面与mysql类似,虽然在几个特征上还是有所不同.客户机程序5在输入上有几个约束条件: ■ 每个输入行必须包括一个完整的查询. ■ 查询不会以分号或' g'为终止. ■ 不识别类似quit 的命令:而是

单片机-基于51系列的电阻筛选器怎么样求详细

问题描述 基于51系列的电阻筛选器怎么样求详细 程序中设定好范围,直接检测看结果. 如设定范围10--11K,待测电阻10K.在范围内绿灯亮,不在红灯亮.求具体求大神 解决方案 这个要设计电路部分只有单片机肯定不行 解决方案二: 串电阻,分压.单片机AD采集后,根据电压大小,根据公式测出电阻大小,再进行点灯...不知可否.

HDwiki系列讲座第九期: 网络广告联盟广告投放技巧

中介交易 SEO诊断 淘宝客 云主机 技术大厅 大家好,很荣幸能担任本次讲座的嘉宾,由于讲座的主题是"网络广告联盟广告投放技巧",所以,我还是要先给大家简单介绍一下什么是网络广告联盟. 下面开始进入主题 一.什么是网络广告联盟 网络广告联盟,又称联盟营销,指集合中小网络媒体资源(又称联盟会员,如中小网站.个人网站.WAP 站点等)组成联盟,通过联盟平台帮助广告主实现广告投放,并进行广告投放数据监测统计, 广告主则按照网络广告的实际效果向联盟会员支付广告费用的网络广告组织投放形式. 网络

Java Socket+mysql实现简易文件上传器的代码_java

最近跟着某网站学习了一个小项目,因为白天有课,所以都是晚上写的,今天把它完成了. 项目主要是实现一个文件上传器,通过客户端的登陆,把本地文件上传到服务器的数据库(本地的). 首先建两个表如下: 一个文件信息表 CREATE TABLE `fileinfo` ( `Fname` char(50) NOT NULL, `FInfo` blob NOT NULL, `FId` int(10) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`FId`) ) ENGINE=I