假设我们有两个数据表t1和t2,每个有1000行,包含的值从1到1000。下面的查询查找出两个表中值相同的数据行:
mysql> SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2; +------+------+ | i1 | i2 | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 |
两个表都没有索引的时候,EXPLAIN产生下面的结果:
mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t1 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: *************************** 2. row *************************** id: 1 select_type: SIMPLE table: t2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using whe
类型列中的ALL表明要进行检查所有数据行的全表扫描。可能键列中的NULL表明没有找到用于提高查询速度的备选索引(键、键长度和参考列都是NULL也是因为缺少合适的索引)。Using where表明使用WHERE子句中的信息来识别合格的数据行。 这段信息告诉我们,优化器没有为提高执行查询的效率找到任何有用的信息:
它将对t1表进行全表扫描。
对于t1中的每一行,它将执行t2的全表扫描,使用WHERE子句中的信息识别出合格的行。
行数值显示了优化器估计的每个阶段查询需要检查的行数。T1的估计值是1000,因为1000可以完成全表扫描。相似地,t2的估计值也是1000,但是这个值是对于t1的每一行的。换句话说,优化器所估计的处理该查询所需要检查的数据行组合的数量是1000×1000,也就是一百万。这会造成很大的浪费 ,因为实际上只有1000个组合符合WHERE子句的条件。
为了使这个查询的效率更高,给其中一个联结列添加索引 并重新执行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: 1 select_type: SIMPLE table: t1 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: *************************** 2. row *************************** id: 1 select_type: SIMPLE table: t2 type: ref possible_keys: i2 key: i2 key_len: 5 ref: sampdb.t1.i1 rows: 10 Extra: Using where; Using index
我们可以看到性能提高了。T1的输出没有改变(表明还是需要进行全表扫描),但是优化器处理t2的方式就有所不同了:
类型从ALL改变为ref,意味着可以使用参考值(来自t1的值)来执行索引查找,定位t2中合格的数据行。
参考值在参考(ref)字段中给出了:sampdb.t1.i1。
数值从1000降低到了10,显示出优化器相信对于t1中的每一行,它只需要检查t2中的10行(这是一个悲观的估计值。实际上,在t2中只有一行与 t1中数据行匹配。我们在后面会看到如何帮助优化器改善这个估计值)。数据行组合的全部估计值使1000×10=10000。它比前面的没有索引的时候估 计出来的一百万好多了。
对t1进行索引有价值吗?实际上,对于这个特定的联结操作,扫描一张表是必要的,因此没有必要对t1建立索引。如果你想看到效果,可以索引t1.i1并再次运行EXPLAIN:
mysql> ALTER TABLE t1 ADD INDEX (i1); mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t1 type: index possible_keys: i1 key: i1 key_len: 5 ref: NULL rows: 1000 Extra: Using index *************************** 2. row *************************** id: 1 select_type: SIMPLE table: t2 type: ref possible_keys: i2 key: i2 key_len: 5 ref: sampdb.t1.i1 rows: 10 Extra: Using where; Using index
上面的输出与前面的EXPLAIN的输出相似,但是添加索引对t1的输出有一些改变。类型从NULL改成了index,附加(Extra)从空的改成了 Using index。这些改变表明,尽管对索引的值仍然需要执行全表扫描,但是优化器还是可以直接从索引文件中读取值,根据不需要使用数据文件。你可以从 MyISAM表中看到这类结果,在这种情况下,优化器知道自己只询问索引文件就能够得到所有需要的信息。对于InnoDB 和BDB表也有这样的结果,在这种情况下优化器可以单独使用索引中的信息而不用搜索数据行。
我们可以运行ANALYZE TABLE使优化器进一步优化估计值。这会引起服务器生成键值的静态分布。分析上面的表并再次运行EXPLAIN得到了更好的估计值:
mysql> ANALYZE TABLE t1, t2; mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t1 type: index possible_keys: i1 key: i1 key_len: 5 ref: NULL rows: 1000 Extra: Using index *************************** 2. row *************************** id: 1 select_type: SIMPLE table: t2 type: ref possible_keys: i2 key: i2 key_len: 5 ref: sampdb.t1.i1 rows: 1 Extra: Using where; Using inde
在这种情况下,优化器估计在t2中与t1的每个值匹配的数据行只有一个。
mysql > explain select A . id , A . title , B . title from jos_content A , jos_categories B where A . catid = B . id ; +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+ | 1 | SIMPLE | A | ALL | NULL | NULL | NULL | NULL | 46585 | | | 1 | SIMPLE | B | eq_ref | PRIMARY | PRIMARY | 4 | joomla_test . A . catid | 1 | Using where | +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+ 2 rows in set ( 0.00 sec )
这个是我们经常使用的一种查询方式,对B表的联接类型使用了eq_ref,索引使用了PRIMARY,但是对于A表,却没有使用任何索引,这可能不是我们想要的。
查看以上SQL语句,我们可能会想到,有必要给A.catid加个索引了。
mysql > alter table jos_content add index idx_catid ( ` catid ` ) ; Query OK , 46585 rows affected ( 0.75 sec ) Records : 46585 Duplicates : 0 Warnings : 0 mysql > explain select A . id , A . title , B . title from jos_content A , jos_categories B where A . catid = B . id ; +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+ | 1 | SIMPLE | A | ALL | idx_catid | NULL | NULL | NULL | 46585 | | | 1 | SIMPLE | B | eq_ref | PRIMARY | PRIMARY | 4 | joomla_test . A . catid | 1 | Using where | +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+ 2 rows in set ( 0.00 sec )
mysql > explain select A . id , A . title , B . title from jos_content A , jos_categories B , jos_sections C where A . catid = B . id and A . sectionid = C . id ; +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+--------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+--------------------------------+ | 1 | SIMPLE | C | index | PRIMARY | PRIMARY | 4 | NULL | 2 | Using index | | 1 | SIMPLE | A | ALL | idx_catid | NULL | NULL | NULL | 46585 | Using where ; Using join buffer | | 1 | SIMPLE | B | eq_ref | PRIMARY | PRIMARY | 4 | joomla_test . A . catid | 1 | Using where | +----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+--------------------------------+ 3 rows in set ( 0.00 sec )这里显示了Mysql先将C表读入查询,并使用PRIMARY索引,然后联合A表进行查询,这时候type显示的是ALL,可以用的索引有idx_catid,但是实际没有用。
原因非常明显,因为使用的连接条件是A.sectionid=C.id,所以我们给A.sectionid加个索引先。
mysql > alter table jos_content add index idx_section ( ` sectionid ` ) ; Query OK , 46585 rows affected ( 0.89 sec ) Records : 46585 Duplicates : 0 Warnings : 0 mysql > explain select A . id , A . title , B . title from jos_content A , jos_categories B , jos_sections C where A . catid = B . id and A . sectionid = C . id ; +----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+ | 1 | SIMPLE | C | index | PRIMARY | PRIMARY | 4 | NULL | 2 | Using index | | 1 | SIMPLE | A | ref | idx_catid , idx_section | idx_section | 4 | joomla_test . C . id | 23293 | Using where | | 1 | SIMPLE | B | eq_ref | PRIMARY | PRIMARY | 4 | joomla_test . A . catid | 1 | Using where | +----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+ 3 rows in set ( 0.00 sec )这时候显示结果告诉我们,效果很明显,在连接A表时type变成了ref,索引使用了idx_section,如果我们注意看后两列,对A表的查询结果后一次明显少了一半左右,而且没有用到join buffer。
这个表读入的顺序是Mysql优化器帮我们做的,可以得知,用记录数少的表做为基础表进行联合,将会得到更高的效率。
mysql > explain select A . id , A . title , B . title from jos_content A left join jos_categories B on A . catid = B . id left join jos_sections C on A . sectionid = C . id ; +----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+-------------+ | 1 | SIMPLE | A | ALL | NULL | NULL | NULL | NULL | 46585 | | | 1 | SIMPLE | B | eq_ref | PRIMARY | PRIMARY | 4 | joomla_test . A . catid | 1 | | | 1 | SIMPLE | C | eq_ref | PRIMARY | PRIMARY | 4 | joomla_test . A . sectionid | 1 | Using index | +----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+-------------+ 3 rows in set ( 0.00 sec )Mysql读入表的顺序被改变了,这意味着,如果我们用left join来做连接查询,Mysql会按SQL语句中表出现的顺序读入,还有一个有变化的地方是联接B和C的type都变成了eq_ref,前边我们说过, 这样说明Mysql可以找到唯一的行,这个效率是比ref要高的。
相关推荐
### SQL优化与SQL执行分析工具Explain的使用详解 #### 一、SQL优化的重要性 SQL优化一直是数据库领域的重要话题,特别是在大数据量处理和高并发访问的场景下,优化后的SQL查询能够显著提升系统的响应速度和资源...
### 数据库面试题索引SQL优化 在数据库领域,尤其是对于从事数据库管理、开发工作的专业人士而言,面试过程中经常会被问及关于SQL查询优化以及索引的相关问题。这些知识点不仅是技术能力的重要体现,也是提高数据库...
### SQL语句性能分析之explain #### 概述 在数据库管理及开发过程中,SQL查询语句的性能优化是一项至关重要的...通过以上方法,我们可以有效地利用`EXPLAIN`来分析和优化SQL查询性能,进而提高数据库的整体运行效率。
本文将深入探讨Oracle索引的原理、创建方法,并结合SQL优化策略,帮助你提升数据库查询速度,降低资源消耗。 首先,我们要理解索引的基本概念。在数据库中,索引类似于书籍的目录,它为数据提供快速访问的途径。...
### MySQL性能优化与SQL优化方法技巧 #### 一、引言 MySQL作为一款广泛使用的开源关系型数据库管理系统,其性能优化对于确保应用系统的稳定性和高效运行至关重要。通过对MySQL的优化,不仅能提升系统的响应速度,还...
综上所述,这些资料涵盖了从基础到高级的SQL优化和数据库性能提升方法,对于数据库管理员、开发人员和面试者来说,都是非常宝贵的学习资源。理解和掌握这些知识点,不仅可以提高面试成功率,还能在实际工作中提升...
### MySQL数据库SQL优化 #### 一、SQL优化 在MySQL数据库管理中,SQL查询的性能直接影响到系统的响应时间和资源消耗。通过合理的SQL优化,可以显著提高数据处理速度,降低服务器负载,提升用户体验。 ##### 1.1 ...
### Oracle数据库基于索引SQL优化方法的研究与实现 #### 一、引言 随着信息技术的发展,数据库管理系统(DBMS)在企业级应用中的地位越来越重要。Oracle数据库作为一种高性能的关系型数据库管理系统,在众多领域得到...
以上内容涵盖了SQL优化公开课1中的核心知识点,包括如何定位Top-SQL、会话跟踪、解读执行计划、统计信息分析、全表扫描优化、索引优化、直方图的应用以及稳定执行计划的方法。通过学习这些知识,可以有效地提高...
根据提供的文件信息,本文将对《基于Oracle的SQL优化》这一主题进行深入解析,包括但不限于SQL优化的重要性、Oracle数据库的特点以及具体的SQL优化方法等。 ### SQL优化的重要性 SQL(Structured Query Language)...
在《SQL语句的优化方法.doc》中,可能会深入讲解各种优化技巧,例如使用EXPLAIN PLAN分析查询执行计划,识别慢查询,以及如何通过调整WHERE子句、JOIN条件或GROUP BY子句来改进查询性能。此外,文档可能还会提及如何...
首先,我们要明白SQL优化的基本原则:减少查询次数、减小数据量、合理设计索引以及优化查询语句结构。这四个原则贯穿于整个SQL优化过程,是提升查询效率的基础。 1. 减少查询次数:通过联合查询、子查询优化和存储...
3. **执行计划分析**:通过EXPLAIN PLAN或V$SQL_PLAN视图来分析SQL的执行路径,理解成本基数、选择性、访问方法等概念。 4. **SQL性能分析**:使用Oracle的性能监控工具,如V$SESSION_WAIT、ASH(Active Session ...
- **案例1:索引优化**:通过添加或调整索引来提高查询速度。 - **案例2:查询重写**:重构查询逻辑以减少不必要的全表扫描。 - **案例3:使用提示**:利用SQL提示引导优化器选择更优的执行计划。 #### 二、性能...
### MySQL优化之SQL语句与索引优化 #### 数据库设计合理性 在MySQL数据库的优化过程中,合理设计数据库(表)至关...通过综合运用这些优化方法,可以有效提升数据库系统的性能和稳定性,为用户提供更好的服务体验。
1. **SQL执行计划分析**:在Oracle中,通过`EXPLAIN PLAN`语句可以获取SQL查询的执行计划,理解数据是如何被检索和处理的。执行计划包含了表的访问方式(全表扫描、索引扫描等)、连接顺序和操作类型(如排序、并集...
本文主要关注如何找到需要优化的SQL语句,遵循正确的优化原则,并通过实例分析展示优化方法。以下是一些关键知识点: 首先,定位需要优化的SQL语句是优化的第一步。在MariaDB 10.1.21/ColumnStore 1.0.8环境下,...
让我们一起领略"SQL索引降龙十八掌"的精髓。 一、了解索引 1. 索引类型: - B树索引:最常见的索引类型,适用于等值查询。 - bitmap索引:适用于多列组合查询和数据仓库场景。 - 全文索引:用于全文搜索。 - ...
以下是一些常用的SQL优化方法,这些方法将有助于提升数据库性能,减少资源消耗,提高用户体验。 1. **选择正确的索引**:为经常出现在WHERE子句中的列创建索引可以显著加快查询速度。B树、哈希和全文索引都有各自的...