• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Mysql 高级优化之 理解查询执行
 

Mysql 高级优化之 理解查询执行

on

  • 444 views

 

Statistics

Views

Total Views
444
Views on SlideShare
444
Embed Views
0

Actions

Likes
2
Downloads
9
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Mysql 高级优化之 理解查询执行 Mysql 高级优化之 理解查询执行 Presentation Transcript

    • MySQL 高级优化之— 理解查询执行 上海二三四五网络科技股份有限公司 互联网研发中心 王德玖 2013-10-11 www.2345.com
    • 议程 • • • • Mysql 实例数据库安装 Explain介绍 举例 问答 2 www.2345.com
    • 实例数据库安装 • 本ppt使用 sakila 数据库为事例; • 下载地址: http://downloads.mysql.com/docs/sakila-db.tar.gz • 安装事例数据库: • [root@locahost]# tar -xzvf sakila.sql.tar.gz • mysql> source /opt/src/sakila/ sakila-schema.sql • mysql> source /opt/src/sakila/ sakila-data.sql • 内网ip:172.16.0.230 已经安装此测试库 3 www.2345.com
    • Explain 输出介绍 • • • • • • • • • • id :表的序列号标识 select_type: SELECT 的类型 table: table 或者 alias 的名称 type :连接的查询类型(本次重点) possible_keys: 有哪些mysql可用的索引 keys : MySQL 执行时实际使用的索引 key_len: 使用到的索引长度 Ref:哪些字段被用来和 key配合从表中获取结果集 Rows:查询需要扫描的估计行数 extra: 其他的附加信息 4 www.2345.com
    • Explain 输出 type • SELECT 查询的访问类型 • 各种方法: • system/const 好 • eq_ref • ref • ref_or_null • index_merge • range • index • ALL 坏 5 www.2345.com
    • Explain实例 root@localhost: >EXPLAIN SELECT * FROM rental INNER JOIN inventory ON > rental.inventory_id = inventory.inventory_id WHERE rental_date BETWEEN '2006-03-01' AND '2006-08-01'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: range possible_keys: rental_date,idx_fk_inventory_id key: rental_date key_len: 8 查询Tpye ref: NULL rows: 1 range Extra: Using where eq_ref *************************** 2. row *************************** id: 1 select_type: SIMPLE table: inventory type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 3 ref: sakila.rental.inventory_id rows: 1 Extra: 2 rows in set (0.00 sec) 6 类型: www.2345.com
    • 查询类型 – 避免 “ALL” • Type这一列是explain 输出的最重要的信息 • 它告诉我们mysql选择怎么样访问策略来获 取特定的结果 – Type 为“ALL”意味着什么呢? – 这一提示表示mysql获取结果需要进行一次全 表扫描 – 下页为一个全表扫描的实例 ... www.2345.com
    • 全表扫描type:ALL root@localhost: sakila 01:21:19>EXPLAIN SELECT * FROM rental G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental 这里,我们看到了一个全表扫 type: ALL 描的的执行计划。在这个场景 possible_keys: NULL 中,没有给定where子句,查 key: NULL key_len: NULL 询优化器没有使用索引来过滤 ref: NULL 行。因此,注意, SELECT * rows: 16451 FROM rental 和下面我们将要 Extra: 1 row in set (0.00 sec) 给出的 ‘ SELECT rental_date from rental ’ ,仅仅选择一列的 效率是不一样的 … www.2345.com
    • 查询类型 – ’INDEX’ 扫描 • ‘INDEX’ 扫描并不是很好的查询类型 – 它提示在表的索引上进行了一次全索引扫描 – 当然它比全表扫描来说性能要好,但是依然需 要消耗大量资源 – 下页为一个全索引扫描的实例 ... www.2345.com
    • 全索引扫描type:INDEX root@localhost: sakila 01:21:23>EXPLAIN SELECT rental_date FROM rental G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: index 这里,我们看到了一个全索引扫 possible_keys: NULL 描的执行计划。通过指定我们仅 key: rental_date key_len: 13 想要的列,其实这就是告诉 ref: NULL mysql查询优化器,如果查询的 rows: 16451 列( rental_date )上包含有索引, Extra: Using index 1 row in set (0.00 sec) 那么就不需要表上的其他列,通 过索引自身就可以提供我们需要 的数据 … www.2345.com
    • 原来如此 ”SELECT * …” www.2345.com
    • 范围扫描类型:”RANGE”扫描 范围扫描 “range” 类型特点 指定 WHERE (or ON) 作为范围范围过滤 使用 BETWEEN 操作符 使用 IN() 操作符 带有 >, >=, <, <= 操作符 MySQL 有很多优化范围扫描的操作符,它们 一般访问比较快速 • 但是必须保证在操作的列上有索引 • 下页为一个范围扫描的实例 ... • • • • • • www.2345.com
    • 范围扫描type:RANGE root@localhost: sakila 02:53:19>EXPLAIN SELECT * FROM rental ->WHERE rental_date BETWEEN '2006-01-01' AND '2006-07-01'G *************************** 1. row *************************** id: 1 select_type: SIMPLE 这里我们看到一个范围扫描的 table: rental type: range 查询计划。 BETWEEN 操作符 possible_keys: rental_date 表示我们想要的数据在rental key: rental_date date 的某一范围之间。注意 key_len: 8 ref: NULL possible_keys 列提示有一个索 rows: 2614 引在 rental_date上,可以 为 Extra: Using where 优化器提供范围扫描匹配,如 1 row in set (0.00 sec) 果没有这个索引,情况又将如 果何呢? www.2345.com
    • 怎么样?回到了 ’ALL’ root@localhost: sakila 02:53:19> DROP INDEX rental_date ON rental; Query OK, 16044 rows affected (1.20 sec) Records: 16044 Duplicates: 0 Warnings: 0 mysql> EXPLAIN SELECT * FROM rental -> WHERE rental_date BETWEEN '2006-01-01' AND '2006-07-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: ALL 因为rental_date 列没 possible_keys: NULL 有了索引,查询优化 key: NULL key_len: NULL 器不再使用范围扫描, ref: NULL 而回到了全表扫描, rows: 16462 可见恰当的索引是多 Extra: Using where 1 row in set (0.01 sec) 么重要 www.2345.com
    • 合并索引类型 - ”index_merge” • 合并索引扫描 “index_merge” 类型特点 – 这一特性在mysql5.0以上版本才有 – 它的优势是在一张表上可以同时使用多个索引 • 在mysql5.0之前一张表上的查询近能使用一个索引 – 在or 类型的操作中很有帮助 – 下页看一个index_merge实例 ... www.2345.com
    • 合并索引扫描 :index_merge root@localhost: sakila 03:27:44>EXPLAIN SELECT * FROM rental -> WHERE rental_id IN (10,11,12) -> OR rental_date = '2006-02-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: index_merge possible_keys: PRIMARY,rental_date key: rental_date,PRIMARY key_len: 8,4 ref: NULL rows: 4 Extra: Using sort_union(rental_date,PRIMARY); Using where 1 row in set (0.02 sec) 这里使用了和并 索引扫描,优化 器使用到了连个 索引,在 mysql5.0之前之 能使用一个索引 www.2345.com
    • 合并索引index_mereg 续… • 它可以在用于 – sort_union • 如前例子,或者是条件使用范围的非主键的列 – Union • OR 条件使用常量或范围条件是主键列并且是innodb表 – Intersection • AND 条件使用常量或范围条件是主键列且是innodb表 • 不能在全文索引上使用 • 可以使用下面的参数来关闭之 – optimizer_switch = index_merge=on,index_merge_union=on,index_merge_sort_u nion=on,index_merge_intersection=on www.2345.com
    • Ref类型扫描 • 根据键值返回的结果集不大的情况 • 在索引列上有一个常量的时候(见下例) • 通过连接表的索引来访问另一个连接表的 时候(见后例) • 通过索引搜索或者多连接单独扫描时 www.2345.com
    • Ref类型扫描实例( on indexed 列 ) root@localhost: sakila 04:40:44>EXPLAIN SELECT * FROM rental ->WHERE rental_id IN (10,11,12) -> AND rental_date = '2006-02-01'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: ref 这里有两个可选索引供优化 possible_keys: PRIMARY,rental_date 器过滤记录选用,但是优化 key: rental_date key_len: 8 器选用rental_date,先从此 ref: const 索引中搜索出符合条件的记 rows: 1 录,根据索引再找出基于in() Extra: Using where 1 row in set (0.00 sec) 表达式中相应记录过滤出结 果集 www.2345.com
    • Ref类型扫描实例( on join ) root@localhost: : sakila >EXPLAIN SELECT * FROM rental -> INNER JOIN inventory ON inventory.inventory_id=rental.inventory_id G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: inventory type: ALL possible_keys: PRIMARY key: NULL key_len: NULL ref: NULL rows: 4645 Extra: *************************** 2. row *************************** id: 1 select_type: SIMPLE table: rental type: ref possible_keys: idx_fk_inventory_id key: idx_fk_inventory_id key_len: 3 ref: sakila.inventory.inventory_id rows: 1 Extra: 2 rows in set (0.00 sec) 这是一个ref扫描的的实例, 它通过外表(inventory)连 接到(rental)表索引列来 查询。值得注意的是,虽然 我们把rental 表作为第一个 from 子句,但是执行计划依 然挑选inventory作为第一张 表进入,这是为什么呢?因 为行数少 … www.2345.com
    • eq_ref类型扫描 • 从一表中读出一行记录以和前一个表中读 取出来的记录做联合 • Where条件用于做连接的列是一个primary key 或 unique 类型 • 直接看实例 … www.2345.com
    • eq_ref类型扫描实例 root@localhost: sakila 09:48:41> EXPLAIN SELECT f.film_id, f.title, c.name > FROM film f INNER JOIN film_category fc > ON f.film_id=fc.film_id INNER JOIN category c > ON fc.category_id=c.category_id WHERE f.title LIKE 'T%' G *************************** 1. row *************************** select_type: SIMPLE table: c type: ALL possible_keys: PRIMARY key: NULL key_len: NULL ref: NULL rows: 16 Extra: *************************** 2. row *************************** select_type: SIMPLE table: fc type: ref possible_keys: PRIMARY,fk_film_category_category key: fk_film_category_category key_len: 1 ref: sakila.c.category_id rows: 1 Extra: Using index *************************** 3. row *************************** select_type: SIMPLE table: f type: eq_ref possible_keys: PRIMARY,idx_title key: PRIMARY key_len: 2 ref: sakila.fc.film_id rows: 1 Extra: Using where 我们注意到,第三行显示使用 了eq_ref访问,即使在作为 where条件的„film.title „有一可 用索引,但是优化器选择使用 primary key,这是为什么呢? 其实我们可以看到在表 category中有16行,通过 film_category表的链接列能够 快速获取数据,16列比通过 tittle索引过滤得到的结果集46 行要少。 www.2345.com
    • 一个重要的分割索引列 mysql> EXPLAIN SELECT * FROM film WHERE title LIKE 'Tr%'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: film 得到一个不错的范围查询,tittle上的 type: range 索引得到使用 possible_keys: idx_title key: idx_title key_len: 767 ref: NULL rows: 15 Extra: Using where mysql> EXPLAIN SELECT * FROM film WHERE LEFT(title,2) = 'Tr' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: film 情况就不乐观了,索引没有得以使用, type: ALL 导致全表扫描为什么呢? possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 951 Extra: Using where www.2345.com
    • index_subquery 和 unique_subquery • 它们出现在SELECT 的子查询中 • 子查询出现唯一结果集的时候为 unique_subquery,否则是index_subquery – unique_subquery的性能稍好,因为优化器可以 把子查询替换成常量集 – 因此,它变成了一个范围条件 • 通常,连接会有更好的性能 • 下面将展示它们的具体情况 www.2345.com
    • unique_subquery访问实例 root@localhost: sakila > EXPLAIN SELECT * FROM rental r WHERE r.customer_id IN ( -> SELECT customer_id FROM customer WHERE last_name LIKE 'S%') G *************************** 1. row *************************** id: 1 select_type: PRIMARY table: r type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 15646 Extra: Using where *************************** 2. row *************************** id: 2 select_type: DEPENDENT SUBQUERY table: customer type: unique_subquery possible_keys: PRIMARY,idx_last_name key: PRIMARY key_len: 2 ref: func rows: 1 Extra: Using index; Using where 外表(rental)通过一个全表扫描, 并通过customer_id 常量集,where过 滤后,把此结果集应用到子查询中的 select,逐个进行自查询。注意,这里 的查询类型提示为依赖子查询 (DEPENDENT SUBQUERY),从技 术上说,这是不正确的,因为这里的 子查询不是相关子查询,而应该返回 一个常量列表。因此,这个查询的 “customer.last_name”上的索引没有仸 何价值 … www.2345.com
    • 重写子查询为标准join root@localhost: sakila> EXPLAIN SELECT * FROM rental r -> INNER JOIN customer c ON r.customer_id=c.customer_id WHERE last_name LIKE 'S%' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: c type: range possible_keys: PRIMARY,idx_last_name key: idx_last_name key_len: 137 ref: NULL rows: 54 Extra: Using where *************************** 2. row *************************** id: 1 select_type: SIMPLE table: r type: ref possible_keys: idx_fk_customer_id key: idx_fk_customer_id key_len: 2 ref: sakila.c.customer_id rows: 13 Extra: 优化器为标准连接给 了一个更好的执行计 划,并且有相同的查 询结果。这一方法值 得推荐-把相关子查询 重写为标准连接查询 www.2345.com
    • 下讲引题 mysql> EXPLAIN SELECT r.staff_id, COUNT(*) -> FROM rental r GROUP BY r.staff_id G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: r type: index possible_keys: NULL key: idx_fk_staff_id key_len: 1 ref: NULL rows: 15646 Extra: Using index mysql> EXPLAIN SELECT r.return_date, COUNT(*) -> FROM rental r GROUP BY r.return_date G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: r type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 15646 Extra: Using temporary; Using filesort 我们注意到 Extra:的信息 完全不一样,这 是为什么呢? … www.2345.com
    • 总结 • • • • 上面我们看了一系列explain输出的type 这是mysql执行计划里非常总要的信息 还有其他列的含义如何 尤其Extra: , key: www.2345.com
    • 结束 Q&A 29 www.2345.com
    • 谢谢 30 www.2345.com