MySQL之查询性能优化四

MySQL的万能"嵌套循环"并不是对每种查询都是最优的。不过还好,mysql查询优化器只对
少部分查询不适用,而且我们往往可以通过改写查询让mysql高效的完成工作。
在这我们先来看看mysql优化器有哪些局限性:

1.关联子查询

mysql的子查询实现得非常糟糕。最糟糕得一类查询是where条件中包含in()的子查询语句。
例如,我们希望找到sakila数据库中,演员Penlope Guiness参演的所有影片信息。
很自然的,我们会按照下面的方式用子查询实现:

   select * from sakila.film
  where film_id in (
    select film_id from sakila.film_actor where actor_id = 1
  )

你很容易认为mysql应该由内而外的去执行这个查询,通过子查询中的条件先找出所匹配的
film_id。所以你看你会认为这个查询可能会是这样:

-- SELECT GROUP_CONCAT(film_id) FROM sakila.film_actor WHERE actor_id = 1;
-- Result: 1,23,25,106,140,166,277,361,438,499,506,509,605,635,749,832,939,970,980
SELECT * FROM sakila.film
WHERE film_id
IN(1,23,25,106,140,166,277,361,438,499,506,509,605,635,749,832,939,970,980);

不幸的是,事实恰恰相反。MYSQL想通过外部的关联条件用来快速的筛选子查询,它可能认为
这会让子查询更效率。mysql会这样重写查询:

SELECT * FROM sakila.film
WHERE EXISTS (
SELECT * FROM sakila.film_actor WHERE actor_id = 1
AND film_actor.film_id = film.film_id);

这样的话,子查询将会依赖外部表的数据,而不会被优先执行。
mysql将会全表扫描film表,然后循环执行子查询。在外表很小的情况下,
不会有什么问题,但在外表很大的情况下,性能将会非常差。幸运的是,
很容易用关联查询来重写。

mysql> SELECT film.* FROM sakila.film
  -> INNER JOIN sakila.film_actor USING(film_id)
  -> WHERE actor_id = 1;

其他的好的优化方法是用group_concat手工生成in()的列表。有时甚至会比JOIN查询
更快。总之,虽然in()子查询在很多情况下工作不佳,但exist()或者其他等价的子查询
有时也工作的不错。

关联子查询性能并不是一直都很差的。

子查询 VS 关联查询

--关联子查询
mysql> explain select film_id, language_id from sakila.film
    where not exsits (
      select * from sakila.film_actor
      where film_actor.film_id = film.film_id
    )

********************* 1. row ***********************************
id : 1
select_type: PRIMARY
table: film
type: all
possible_keys: null
key: null
key_len: null
ref: null
rows: 951
Extra: Using where

********************* 2. row ***********************************
id : 2
select_type: Dependent subquery
table: film_actor
type: ref
possible_keys: idx_fx_film_id
key: idx_fx_film_id
key_len: 2
ref: film.film_id
rows: 2
Extra: Using where;Using index

--关联查询mysql> explain select film.film_id, film.language_id from sakila.film
    left outer join sakila.film_actor using(film_id)
    where film_actor.film_id is null

********************* 1. row ***********************************
id : 1
select_type: simple
table: film
type: all
possible_keys: null
key: null
key_len: null
ref: null
rows: 951
Extra:

********************* 2. row ***********************************
id : 1
select_type: simple
table: film_actor
type: ref
possible_keys: idx_fx_film_id
key: idx_fx_film_id
key_len: 2
ref: sakila.film.film_id
rows: 2
Extra: Using where;Using index;not exists;

可以看到,这里的执行计划几乎一样,下面是一些细微的差别:
1. 表 film_actor的访问类型一个是Dependent subquery 另一是simple,这对底层存储引擎接口来说,没有任何不同;

2. 对 film表 第二个查询没有using where,但这不重要。using子句和where子句实际上是完全一样的。

3. 第二个表film_actor的执行计划的Extra 有 "Not exists" 这是我们先前提到的提前终止算法,mysql通过not exits优化
来避免在表film_actor的索引中读取任何额外的行。这完全等效于直接使用 not exist ,这个在执行计划中也一样,一旦匹配到一行
数据,就立刻停止扫描

测试结果为:
查询 每秒查询数结果(QRS)
NOT EXISTS 子查询 360
LEFT OUTER JOIN 425
这里显示使用子查询会略慢些。

另一个例子:
不过每个具体地案例会各有不同,有时候子查询写法也会快些。例如,当返回结果只有一个表的某些列的时候。
听起来,这种情况对于关联查询效率也会很好。具体情况具体分析,例如下面的关联,我们希望返回所有包含同一个演员参演的电影
因为电影会有很多演员参演,所以可能返回一些重复的记录。

mysql-> select film.film_id from sakila.film
     inner join sakila.film_actor using (film_id)

我们需要用distinct 和 group by 来移除重复的记录

mysql-> select distinct film.film_id from sakila.film
    inner join sakila.film_actor using (film_id)

但是,回头看看这个查询,到底这个查询返回的结果意义是什么?至少这样的写法会让sql的意义不明显。
如果是有exists 则很容易表达"包含同一个参演演员"的逻辑。而且不需要使用 distinct 和 Group by,也不会有重复的结果集。
我们知道一旦使用了 distinct 和 group by 那么在查询的执行过程中,通常需要产生临时中间表。

mysql -> select film_id from sakila.film_actor
    where exists(select * from sakila.film_actor
    where film.film_id = film_actor.film_id)

测试结果为:
查询 每秒查询数结果(QRS)
INNER JOIN 185
EXISTS 子查询 325
这里显示使用子查询会略快些。

通过上面这个详细的案例,主要想说明两点:
一是不需要听取哪些关于子查询的 "绝对真理",(即别用使用子查询)
二是应该用测试来验证子查询的执行疾患和响应时间的假设。

时间: 2024-10-09 01:55:49

MySQL之查询性能优化四的相关文章

MySQL之查询性能优化

为什么查询速度会慢 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中"执行"可以认为是整个生命周期中最重要的阶段,这其中包括了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序.分组等. 在完成这些任务的时候,查询需要在不同的地方花费时间,包括网络,CPU计算,生成统计信息和执行计划.锁等待(互斥等待)等操作,尤其是向底层存储引擎检索数据的调用操作,这些调用需要在内存操作.CPU操作和内存

MySQL之查询性能优化一

只有当查询优化,索引优化,库表结构优化齐头并进时,才能实现mysql高性能. 在尝试编写快速的查询之前,需要清楚一点,真正重要是响应时间. 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后再服务器上进行解析,生成执行计划,执行,并返回结果给客户端. 其中"执行"可以认为是整个生命周期最重要的阶段,这其中包括了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序,分组等. 对于一个查询的全部生命周期,上面列的并不完整.这里我们只是想说:了解查询的生命周期,

MySQL之查询性能优化五(优化特定类型的查询)

本文将介绍如何优化特定类型的查询. 1.优化count()查询 count()聚合函数,以及如何优化使用了该函数的查询,很可能是mysql中最容易被误解的前10个话题之一 count() 是一个特殊的函数,有两种非常不同的作用.它可以统计某个列值的数量,也可以统计行数. 统计列值 要求列值是非空的.(不统计null,即null值计数为0) count()的另一个用处是统计结果集的行数.当mysql确认括号的表达式值不可能为空时,实际上就是统计 行数.最简单的就是当我们使用count(*)的时候,

MySQL分页查询性能优化

当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点.下面简单说一下我知道的一些方法. 准备工作 为了对下面列举的一些优化进行测试,下面针对已有的一张表进行说明. 表名:order_history 描述:某个业务的订单历史表 主要字段:unsigned int id,tinyint(4) int type 字段情况:该表一共37个字段,不包含text等大型数组,最大为varcha

170727、MySQL查询性能优化

MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下我们从数据库的索引和查询语句的设计两个角度介绍如何提高MySQL查询性能. 数据库索引 索引是存储引擎中用于快速找到记录的一种数据结构.索引有多种分类方式,按照存储方式可以分为:聚簇索引和非聚簇索引:按照数据的唯一性可以分为:唯一索引和非唯一索引:按照列个数可以分为:单列索引和多列索引等.索引也有多

mysql笔记03 查询性能优化

查询性能优化 1. 为什么查询速度会慢? 1). 如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数,要么让子任务运行的更快. 2). 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器端,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中"执行"可以认为是整个生命周期中最重要的阶段,这其中包括 大量为了检索数据到存储引擎的调用以及调用后

高性能mysql 第六章查询性能优化 总结(上)查询的执行过程

6  查询性能优化 6.1为什么查询会变慢 这里说明了的查询执行周期,从客户端到服务器端,服务器端解析,优化器生成执行计划,执行(可以细分,大体过程可以通过show profile查看),从服务器端返回客户端结果. 而执行部分作为最重要的一环,需要做的事情比较多,而不合适的query往往让执行过程做了不必要的操作,或者不能使用更优秀的底层数据结构,从而用时更久. 6.2慢查询基础:优化数据访问 访问数据量多大,超过实际所需是慢查询的一个原因.导致这种情况的原因大致有两个 1.应用程序向mysql

查询性能优化

查询性能优化 怎么样算查询性能比较好?响应时间短(获取查询数据速度快) 优化数据访问 查询性能低下最基本的原因是访问的数据太多.大部分性能低下的查询都可以通过减少访问的数据量的方式进行优化. 对于低效的查询,我们发现通过下面两个步骤来分析总是很有效: 确认应用程序是否在检索大量超过需要的数据.这通常意味着访问了太多行,但有时候也可能是访问了太多的列. 确认MySQL服务器层是否在分析大量超过需要的数据行. 总结:1.只查询了需要的列2.在满足要求的前提下尽可能扫描少的行 是否向数据库请求了不需要

SQL Server 查询性能优化 相关文章

来自: SQL Server 查询性能优化——堆表.碎片与索引(一) SQL Server 查询性能优化——堆表.碎片与索引(二) SQL Server 查询性能优化——覆盖索引(一) SQL Server 查询性能优化——覆盖索引(二) SQL Server 查询性能优化——创建索引原则(一) SQL Server 查询性能优化——创建索引原则(二) SQL Server 查询性能优化——索引与SARG(一) SQL Server 查询性能优化——索引与SARG(二) SQL Server 查