当前位置: 首页 > news >正文

MySQL索引的性能优化

1.数据库服务器的优化步骤

在数据库调优中,我们的目标就是响应时间更快,吞吐量更大。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式

数据库服务器的优化步骤

当我们遇到数据库调优问题的时候,该如何思考呢?这里把思考的流程整理成下面这张图。

整个流程划分成了 观察(Show status) 和行动(Action)两个部分。字母 S 的部分代表观察(会使用相应的分析工具),字母 A 代表的部分是行动(对应分析可以采取的行动)

首先在S1部分,需要观察服务器的状态是否存在周期性的波动。如果存在周期性波动,有可能是周期性节点的原因,比如双十一、促销活动等。这样的话,可以通过A1这一步骤解决,也就是加缓存,或者更改缓存失效策略。

如果缓存策略没有解决,或者不是周期性波动的原因,就需要进一步分析查询延迟和卡顿的原因。接下来进入S2这一步,需要开启慢查询。慢查询可以帮我们定位执行慢的SQL语句。可以通过设置long_query_time参数定义“慢""的阈值,如果SQL执行时间超过了long query_time,则会认为是慢查询。当收集上来这些慢查询之后,就可以通过分析工具对慢查询日志进行分析。

在S3这一步骤中,我们就知道了执行慢的SQL,这样就可以针对性地用EXPLAIN查看对应SQL语句的执行计划,或者使用show profile查看SQL中每一个步骤的时间成本。这样就可以了解SQL查询慢是因为执行时间长,还是等待时间长。

如果是SQL等待时间长,就进入A2步骤。在这一步骤中,可以调优服务器的参数,比如适当增加数据库缓冲池等。如果是SQL执行时间长,就进入A3步骤,这一步中需要考虑是索引设计的问题?还是查询关联的数据表过多?还是因为数据表的字段设计问题导致了这一现象。然后在这些维度上进行对应的调整。
如果A2和A3都不能解决问题,需要考虑数据库自身的SQL查询性能是否已经达到了瓶颈,如果确认没有达到性能瓶颈,就需要重新检查,重复以上的步骤。如果已经达到了性能瓶颈,进入A4阶段,需要考虑增加服务器,采用读写分离的架构,或者考虑对数据库进行分库分表,比如垂直分库、垂直分表和水平分表等。

以上就是数据库调忧的流程思路。如果发现执行SQL时存在不规则延迟或卡顿的时候,就可以采用分析工具帮我们定位有问题的SQL,这三种分析工具可以理解是SQL调优的三个步骤:慢查询、EXPLAIN和SHOEW PROFILING

小结:

 2.查询系统性能参数

在MySQL中,`SHOW STATUS`是一个用于显示服务器状态的命令,它可以提供有关服务器运行时的大量信息,包括各种计数器和状态值。这些信息对于诊断问题、性能调优和了解服务器的运行情况非常有用。

使用`SHOW STATUS`时,可以指定不同的参数来过滤显示的信息:

`SHOW STATUS`:显示所有状态变量。

SHOW [GLOBAL|SESSION] STATUS LIKE '参数';

一些常用的性能参数如下:

  • Connections:连接MySQL服务器的次数。
  • Uptime:MySQL服务器的上线时间。
  • Slow_queries:慢查询的次数。
  • Innodb_rows_read:Select查询返回的行数
  • Innodb_rows_inserted:执行INSERT操作插入的行数
  • Innodb_rows_updated:执行UPDATE操作更新的行数
  • Innodb_rows_deleted:执行DELETE操作删除的行数
  • Com_select:查询操作的次数。
  • Com_insert:插入操作的次数。对于批量插入的 INSERT 操作,只累加一次。
  • Com_update:更新操作的次数。
  • Com_delete:删除操作的次数。
  • 若查询MySQL服务器的连接次数,则可以执行如下语句:
SHOW STATUS LIKE 'Connections';
  • 若查询服务器工作时间,则可以执行如下语句:
SHOW STATUS LIKE 'Uptime';
  • 若查询MySQL服务器的慢查询次数,则可以执行如下语句:
SHOW STATUS LIKE 'Slow_queries';

3. 统计SQL的查询成本:last_query_cost

一条SQL查询语句在执行前需要确定查询执行计划,如果存在多种执行计划的话,MySQL会计算每个执行计划所需要的成本,从中选择成本最小的一个作为最终执行的执行计划。


如果想要查看某条SQL语句的查询成本,可以在执行完这条SQL语句之后,通过查看当前会话中的last_query_cost变量值来得到当前查询的成本。它通常也是评价一个查询的执行效率的一个常用指标。这个查询成本对应的是SQL语句所需要读取的页的数量

CREATE TABLE `student_info` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`student_id` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`course_id` INT NOT NULL ,
`class_id` INT(11) DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

如果想要查询 id=900001 的记录,然后看下查询成本,我们可以直接在聚簇索引上进行查找:

SELECT student_id, class_id, NAME, create_time FROM student_info
WHERE id = 900001;
#运行结果(1 条记录,运行时间为 0.042s )

然后再看下查询优化器的成本,实际上我们只需要检索一个页即可:

SHOW STATUS LIKE 'last_query_cost';
/*
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| Last_query_cost | 1.000000 |
+-----------------+----------+
*/

如果要查询 id 在 900001 到 9000100 之间的学生记录呢?

SELECT student_id, class_id, NAME, create_time FROM student_info
WHERE id BETWEEN 900001 AND 900100;

运行结果(100 条记录,运行时间为 0.046s )

然后再看下查询优化器的成本,这时我们大概需要进行 20 个页的查询

 SHOW STATUS LIKE 'last_query_cost';/*
+-----------------+-----------+
| Variable_name | Value       |
+-----------------+-----------+
| Last_query_cost | 21.134453 |
+-----------------+-----------+
*/

能看到页的数量是刚才的 20 倍,但是查询的效率并没有明显的变化,实际上这两个 SQL 查询的时间基本上一样,就是因为采用了顺序读取的方式将页面一次性加载到缓冲池中,然后再进行查找。虽然页数量(last_query_cost)增加了不少 ,但是通过缓冲池的机制,并没有增加多少查询时间 。

使用场景:它对于比较开销是非常有用的,特别是有好几种查询方式可选的时候

SQL查询是一个动态的过程,从页加载的角度来看,可以得到以下两点结论:

  • 位置决定效率。如果页就在数据库缓冲池中,那么效率是最高的,否则还需要从内存或者磁盘中进行读取,当然针对单个页的读取来说,如果页存在于内存中,会比在磁盘中读取效率高很多。
  • 批量决定效率。如果从磁盘中对单一页进行随机读,那么效率是很低的(差不多10ms),而采用顺序读取的方式,批主对页进行读取,平均一页的读取效率就会提升很多,甚至要快于单个页面在内存中的随机读取。

所以说,遇到I/O并不用担心,方法找对了,效率还是很高的。首先要考虑数据存放的位置,如果是经常使用的数据就要尽量放到缓冲池中,其次可以充分利用磁盘的吞吐能力,一次性批量读取数据,这样单个页的读取效率也就得到了提升。

4.定位执行慢的 SQL:慢查询日志

MySQL的慢查询日志,用来记录在MySQL中响应时间超过阈值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10秒以上(不含10秒)的语句,认为是超出了最大忍耐时间值。

它的主要作用是,帮助我们发现那些执行时间特别长的SQL查询,并且有针对性地进行优化,从而提高系统的整体效率。当数据库服务器发生阻塞、运行变慢的时候,检查一下慢查询日志,找到那些慢查询,对解决问题很有帮助。比如一条sql执行超过5秒钟,就算慢SQL,希望能收集超过5秒的sql,结合explain进行全面分析。

默认情况下,MySQL数据库没有开启慢查询日志,需要手动来设置这个参数。如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。

慢查询日志支持将日志记录写入文件。

show variables like 'slow_query_log';
/*
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+
*/

4.1 开启慢查询日志参数

1.开启slow_query_log

在使用前,需要先看下慢查询是否已经开启,使用下面这条命令即可:

show variables like 'slow_query_log';
/*
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+
*/

我们能看到slow_query_log=OFF,可以把慢查询日志打开,注意设置变量值的时候需要使用global,否则会报错:

set global slow_query_log='ON';

再来查看下慢查询日志是否开启,以及慢查询日志文件的位置:

show variables like '%slow_query_log%';+---------------------+-----------------------------------------+
| Variable_name       | Value                                   |
+---------------------+-----------------------------------------+
| slow_query_log      | ON                                      |
| slow_query_log_file | /var/lib/mysql/centos7-mysql-1-slow.log |
+---------------------+-----------------------------------------+
2 rows in set (0.00 sec)

能看到这时慢查询分析已经开启,同时文件保存在/var/lib/mysql/LSLNO1-slow.log 文件中 

2. 修改long_query_time阈值

#测试发现:设置global的方式对当前session的long_query_time失效。对新连接的客户端有效。所以可以一并执行下述语句
set global long_query_time = 1;
show global variables like '%long_query_time%';set long_query_time=1;
show variables like '%long_query_time%';
/*
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
*/

持久化设置:使用set global语句所做的更改在数据库服务器重启之后将不再生效。要使更改持久化,你需要讲新的值添加到MySQL的配置文件中(my.ini或者my.cnf)。

如果不指定存储路径,慢查询日志将默认存储到MySQL数据库的数据文件夹下。如果不指定文件名,默认文件名为hostname-slow.log

4.2 关闭慢日志查询

关闭慢查询日志通常是为了减少数据库的性能开销,因为记录慢查询日志会占用额外的资源。

方式:临时性方式

使用SET语句来设置。
(1)停止MySQL慢查询日志功能,具体SQL语句如下

SET GLOBAL slow_query_log=off;SHOW VARIABLES LIKE '%slow%';
/*
+---------------------------+--------------------------------+
| Variable_name             | Value                          |
+---------------------------+--------------------------------+
| log_slow_admin_statements | OFF                            |
| log_slow_extra            | OFF                            |
| log_slow_slave_statements | OFF                            |
| slow_launch_time          | 2                              |
| slow_query_log            | OFF                            |
| slow_query_log_file       | /var/lib/mysql/LSLNO1-slow.log |
+---------------------------+--------------------------------+
*/
#以及
SHOW VARIABLES LIKE '%long_query_time%';
/*
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
*/

使用命令mysqladmin flush-logs 来重新生成查询日志文件,具体命令如下,执行完毕会在数据目录下重新生成慢查询日志文件

mysqladmin -uroot -p flush-logs slow
# 在打开的条件下,执行上面的语句,才可以看见重置的日志文件
SET GLOBAL slow_query_log=on;

提示:
慢查询日志都是使用mysqladmin flush-logs命令来删除重建的。使用时一定要注意,一旦执行了这个命令,慢查询日志都只存在新的日志文件中,如果需要旧的查询日志,就必须享先备份。

5. 查看 SQL 执行成本:SHOW PROFILE 

这个是一个用来显示服务器性能相关统计信息的命令。使用show profile可以查看服务器在执行sql语句时的资源使用情况,例如cpu时间,块I/O操作,上下文切换等。对于性能调优非常有用。

Show Profile是MySQL提供的可以用来分析当前会话中SQL都做了什么、执行的资源消耗情况的工具,可用于sql调优的测量。默认情况下处于关闭状态,并保存最近15次的运行结果。 

show variables like 'profiling';
/*
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| profiling     | OFF   |
+---------------+-------+
*/

通过设profiling='ON’来开启show profile :

set profiling = 'ON';

show profile使用演示: 

use atguigudb;select * from student where stuno =343455;
--select * from student where name = 'vyituS';
--show profiles;
列出自从服务器启动以来或从上一次执行reset profiling命令以来所有已经记录查询的性能剖析信息/*
+----------+------------+---------------------------------------------+
| Query_ID | Duration   | Query                                       |
+----------+------------+---------------------------------------------+
|        1 | 0.00174700 | show variables like 'profiling'             |
|        2 | 1.52700950 | select * from student where stuno =343455   |
|        3 | 1.20279475 | select * from student where name = 'vyituS' |
+----------+------------+---------------------------------------------+
3 rows in set, 1 warning (0.00 sec)
*/show profile;
用于显示最近执行的查询性能剖析信息,包括了查询周期中的各个阶段所
花费的时间详情,例如解析,优化,执行查询等阶段/*
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000083 |
| Executing hook on transaction  | 0.000004 |
| starting                       | 0.000009 |
| checking permissions           | 0.000006 |
| Opening tables                 | 0.000044 |
| init                           | 0.000004 |
| System lock                    | 0.000008 |
| optimizing                     | 0.000008 |
| statistics                     | 0.000019 |
| preparing                      | 0.000018 |
| executing                      | 1.202507 |
| end                            | 0.000024 |
| query end                      | 0.000005 |
| waiting for handler commit     | 0.000010 |
| closing tables                 | 0.000012 |
| freeing items                  | 0.000023 |
| cleaning up                    | 0.000013 |
+--------------------------------+----------+
17 rows in set, 1 warning (0.00 sec)*/

作用范围:

  • (1)这个命令只是在本会话内起作用,即无法分析本会话外的语句。开启分析功能后,所有本会话中的语句都被分析(甚至包括执行错误的语句),除了SHOW PROFILE和SHOW PROFILES两句本身。
  • (2)profiling是会话级的,当会话结束,与之相关的profiling信息也会随之消失。
  • (3)profiling是针对进程(process)而非线程(threads),因此运行在服务器上的其他服务进程可能会影响分析结果.

show profile的常用查询参数:

  • ALL:显示所有的开销信息。
  • BLOCK IO:显示块IO开销。
  • CONTEXT SWITCHES:上下文切换开销。
  • CPU:显示CPU开销信息。
  • IPC:显示发送和接收开销信息
  • MEMORY:显示内存开销信息。
  • PAGE FAULTS:显示页面错误开销信息。
  • SOURCE:显示和Source_function,Source_file,Source_line相关的开销信息。
  • SWAPS:显示交换次数开销信息。

6. 分析查询语句:EXPLAIN

EXPLAIN是一个常用的sql命令,用于获取数据库执行的详细信息,它可以帮助开发者了解查询的执行计划,包括查询的步骤,数据访问路径,索引使用情况等,这有助于优化查询性能。

有什么用?

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行优化器查询

举例:

CREATE TABLE employees (id INT AUTO_INCREMENT,first_name VARCHAR(50),last_name VARCHAR(50),email VARCHAR(100),hire_date DATE,PRIMARY KEY (id)
);并且我们想要查询所有在 '2000-01-01' 后雇佣的员工。我们可以用以下 SQL 查询来实现这个目标:SELECT  FROM employees WHERE hire_date > '2000-01-01';

 如果我们想知道这个查询是如何被执行的,可以使用 EXPLAIN 命令。下面是 EXPLAIN 的使用方法

EXPLAIN SELECT  FROM employees WHERE hire_date > '2000-01-01';

假设 employees 表上没有针对 hire_date 的索引,那么 EXPLAIN 的输出可能类似于下面这样:

+----+-------------+----------+----+------+---------------+---------+---------+-------+--------+----------+
| id | select_type | table    | type | possible_keys | key     | key_len | ref   | rows   | filtered | Extra   |
+----+-------------+----------+----+------+---------------+---------+---------+-------+--------+----------+
|  1 | SIMPLE      | employees| ALL | NULL          | NULL    | NULL    | NULL  | 100000 |   10.00 | Using where |
+----+-------------+----------+----+------+---------------+---------+---------+-------+--------+----------+
  • - id: 1 - 查询的选择序列号。
  • - select_type: SIMPLE - 这个查询是最简单的 SELECT 类型。
  • - table: employees - 被查询的表名。
  • - type: ALL - 表明这是一个全表扫描,因为没有合适的索引来加速查询。
  • - possible_keys: NULL - 没有可用的索引。
  • - key: NULL - 没有使用任何索引。
  • - key_len: NULL - 因为没有使用索引,所以这个值也是 NULL。
  • - ref: NULL - 没有使用索引或者常量来查找行。
  • - rows: 100000 - 预计需要检查的行数(假设表中有 100,000 行数据)。
  • - filtered: 10.00 - 过滤掉的行百分比(这里意味着大约 10% 的行将通过 WHERE 子句的过滤)。
  • - Extra: Using where - 表明 WHERE 子句中的条件是在表扫描过程中应用的。

 从上面的输出可以看出,由于没有针对 hire_date 字段的索引,查询需要进行全表扫描,这可能会很慢如果表很大。为了优化查询,我们可以添加一个索引:

ALTER TABLE employees ADD INDEX idx_hire_date (hire_date);

再次运行 EXPLAIN 命令,这次查询计划可能会变得更高效:

EXPLAIN SELECT  FROM employees WHERE hire_date > '2000-01-01';+----+-------------+----------+--------+---------------+---------+---------+-------+------+----------+----------------+
| id | select_type | table    | type   | possible_keys | key     | key_len | ref   | rows | filtered | Extra          |
+----+-------------+----------+--------+---------------+---------+---------+-------+------+----------+----------------+
|  1 | SIMPLE      | employees| range  | idx_hire_date | idx_hire_date | 5      | NULL | 10000    | 100.00         | Using where; Using index |
+----+-------------+----------+--------+---------------+---------+---------+-------+------+----------+----------------+

这次的输出显示:

  • - type: range - 使用了索引范围扫描。
  • - possible_keys: idx_hire_date - 可用的索引。
  • - key: idx_hire_date - 使用的索引。
  • - key_len: 5 - 索引使用的字节数(日期类型的索引长度通常是 5 字节)。
  • - rows: 10000 - 预计需要检查的行数减少了很多。
  • - Extra: Using where; Using index - 表明 WHERE 子句的条件使用了索引,同时也表示查询结果可以直接从索引中获取而不需要访问实际的数据行。

合适的场景使用:

EXPLAIN 在多种情况下都非常有用,特别是在需要优化查询性能的情况下。以下是几种 EXPLAIN 特别有效的场景:

 1. 复杂查询

对于包含多个表连接、子查询或联合操作的复杂查询,EXPLAIN 可以帮助你理解查询优化器是如何处理这些组件的。你可以查看每个表的连接类型、索引使用情况等,从而确定是否有可能进一步优化查询。

 2. 性能瓶颈

如果你发现某个查询特别慢,使用 EXPLAIN 可以帮助识别问题所在。例如,如果 EXPLAIN 显示查询正在执行全表扫描(type: ALL),那么添加适当的索引可能会显著提高查询速度。

 3. 索引评估

当你考虑添加新索引或调整现有索引时,EXPLAIN 是一个很好的工具来评估这些变化的效果。通过比较添加索引前后的 EXPLAIN 输出,你可以看到索引是否被利用以及查询性能的改进程度。

举例:

让我们来看一个具体的例子。假设我们有一个包含两个表的简单数据库:orders 和 customers。

CREATE TABLE orders (order_id INT AUTO_INCREMENT,customer_id INT,order_date DATE,PRIMARY KEY (order_id),FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);CREATE TABLE customers (customer_id INT AUTO_INCREMENT,name VARCHAR(50),address VARCHAR(100),PRIMARY KEY (customer_id)
);

假设我们需要找出所有在2020年下单的客户的名字和地址。我们可以编写如下的查询:

SELECT c.name, c.address
FROM customers AS c
JOIN orders AS o ON c.customer_id = o.customer_id
WHERE o.order_date BETWEEN '2020-01-01' AND '2020-12-31';

现在,我们使用 EXPLAIN 来查看这个查询的执行计划:

EXPLAIN SELECT c.name, c.address
FROM customers AS c
JOIN orders AS o ON c.customer_id = o.customer_id
WHERE o.order_date BETWEEN '2020-01-01' AND '2020-12-31';

如果没有针对 order_date 的索引,EXPLAIN 输出可能显示全表扫描或低效的连接类型。为了提高性能,我们可以为 orders 表添加一个索引:

ALTER TABLE orders ADD INDEX idx_order_date (order_date);

6.1 EXPLAIN的进一步使用

这里谈谈EXPLAIN的输出格式。EXPLAIN可以输出四种格式: 传统格式 , JSON格式 , TREE格式 以及可视化输出 。用户可以根据需要选择适用于自己的格式

1.传统格式

传统格式(Text Format)是 EXPLAIN 命令最常用的输出格式,它以文本形式显示查询计划。这种格式提供了查询中各个步骤的简要描述,并且通常包含有关操作类型、关联的表、使用的索引等信息。

示例:

假设有一个简单的 SQL 查询:

SELECT  FROM employees WHERE department = 'engineering';

我们可以使用 EXPLAIN 命令查看其执行计划:

EXPLAIN SELECT  FROM employees WHERE department = 'engineering';

假定数据库返回的输出类似于下面的内容:

+----+-------------+----------+--------+------------------+------------------+---------+------+---------+-------------+
| id | select_type | table    | type   | possible_keys    | key              | key_len | ref  | rows    | filtered    | Extra       |
+----+-------------+----------+--------+------------------+------------------+---------+------+---------+-------------+
|  1 | SIMPLE      | employees| range  | department       | department       | 100     | NULL | 1000    | 10.00       | Using where |
+----+-------------+----------+--------+------------------+------------------+---------+------+---------+-------------+

 解释

  • - id: 1 - 这个查询块是主查询。
  • - select_type: SIMPLE - 这是一个简单的查询。
  • - table: employees - 查询涉及的表。
  • - type: range - 数据库将使用索引进行范围查找。
  • - possible_keys: department - 可能使用的索引是 department。
  • - key: department - 实际上使用了 department 索引。
  • - key_len: 100 - 使用的索引键的最大长度为 100 字节。
  • - ref: NULL - 没有使用引用。
  • - rows: 1000 - 数据库估计需要检查 1000 行。
  • - filtered: 10.00 - 大约只有 10% 的行满足条件。
  • - Extra: Using where - 查询使用了 WHERE 子句来过滤数据。

2.JSON格式 

JSON 格式是一种结构化的数据格式,常用于网络传输和配置文件中。当使用 EXPLAIN 命令时,JSON 格式可以提供一种易于解析的数据结构,方便开发人员和自动化工具进一步处理查询计划信息。

 JSON 格式的结构

JSON 格式的查询计划通常包含以下主要部分:

  • - query_block: 主查询块的信息,包括选择类型、涉及的表及其访问类型等。
  • - table: 关联表的信息,如表名、索引使用情况等。
  • - nested loop: 对于涉及子查询的情况,可能包含嵌套循环的信息。

 示例

假设我们有如下 SQL 查询:

SELECT  FROM employees WHERE department = 'engineering';

我们可以使用 EXPLAIN 命令并指定 JSON 格式来查看其执行计划:

EXPLAIN FORMAT=JSON SELECT  FROM employees WHERE department = 'engineering';

 输出示例

下面是该查询的一个可能的 JSON 格式输出:

{"query_block": {"select_id": 1,"table": {"table_name": "employees","access_type": "range","possible_keys": ["department"],"key": "department","key_len": "100","ref": null,"rows_examined": 1000,"rows_produced_per_join": 100,"filtered": "10.00","Extra": "Using where"}}
}

 解释

- query_block: 主查询块的信息。

  - select_id: 1 - 查询块的 ID。

  - table: 关联表的信息。

    - table_name: "employees" - 查询涉及的表。

    - access_type: "range" - 数据库将使用索引进行范围查找。

    - possible_keys: ["department"] - 可能使用的索引列表。

    - key: "department" - 实际使用的索引。

    - key_len: "100" - 使用的索引键的最大长度。

    - ref: null - 没有使用引用。

    - rows_examined: 1000 - 数据库估计需要检查的行数。

    - rows_produced_per_join: 100 - 每次连接产生的行数。

    - filtered: "10.00" - 大约只有 10% 的行满足条件。

    - Extra: "Using where" - 查询使用了 WHERE 子句来过滤数据

3.Tree格式 

TREE 格式是 EXPLAIN 命令的一种输出格式,它以树状结构来表示查询计划。这种格式对于理解复杂的嵌套查询特别有用,因为它能够清晰地展示查询的层次结构。

 TREE 格式的结构

TREE 格式的输出通常包含以下元素:

- 操作节点: 每个操作节点都代表查询计划中的一个操作,如表扫描、索引扫描、嵌套循环连接等。

- 属性: 每个操作节点下面列出与该操作相关的属性,如表名、索引、连接条件等。

- 子节点: 复杂的操作可能包含子节点,例如嵌套循环连接中的内部和外部表。

SELECT e.name, d.department_name 
FROM employees e 
JOIN departments d ON e.department_id = d.department_id 
WHERE e.salary > 50000;

 我们可以使用 EXPLAIN 命令并指定 TREE 格式来查看其执行计划:

EXPLAIN (FORMAT TREE) SELECT e.name, d.department_name 
FROM employees e 
JOIN departments d ON e.department_id = d.department_id 
WHERE e.salary > 50000;

输出: 

QUERY PLAN
└─ Nested Loop  (cost=0.00..10000.00 rows=100 width=100)├─ Index Scan using idx_salary on employees e  (cost=0.00..5000.00 rows=100 width=100)│   ├─ Filter: (e.salary > 50000)└─ Index Scan using pk_departments on departments d  (cost=0.00..100.00 rows=1 width=100)├─ Index Cond: (d.department_id = e.department_id)

- QUERY PLAN: 查询计划的根节点。

- Nested Loop: 嵌套循环连接操作,表示将两个表连接在一起。

  - Index Scan using idx_salary on employees e: 索引扫描操作,使用名为 idx_salary 的索引来访问 employees 表。

    - Filter: 过滤条件 (e.salary > 50000)。

  - Index Scan using pk_departments on departments d: 索引扫描操作,使用名为 pk_departments 的索引来访问 departments 表。

    - Index Cond: 索引条件 (d.department_id = e.department_id)。

相关文章:

MySQL索引的性能优化

1.数据库服务器的优化步骤 在数据库调优中,我们的目标就是响应时间更快,吞吐量更大。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候,该如何思考呢&#xf…...

协方差详解及在日常生活中的应用实例——天气温度与冰淇淋销量的关系

协方差详解及在日常生活中的应用实例——天气温度与冰淇淋销量的关系 文章目录 协方差详解及在日常生活中的应用实例——天气温度与冰淇淋销量的关系引言协方差的概念与背景数学公式推导实例背景数据收集计算过程结果解释计算相关系数为什么使用协方差?结论商业启示…...

Spring Boot3.3.X整合Mybatis-Plus

前提说明&#xff1a; 项目的springboot版本为&#xff1a;<version>3.3.2</version> 需要整合的mybatis-plus版本&#xff1a;<version>3.5.7</version> 废话不多说&#xff0c;开始造吧 1.准备好数据库和表 2.配置全局文件application.properti…...

快速了解软件测试——测试用例的方法

测试用例的编写方法有八种&#xff0c;其中等价类、边界值、判定表、场景法、流程图重要且使用得多 ●等价类●边界值●判定表●因果图[了解]●正交法[了解]●场景法●流程图●错误推测法[了解] 1、等价类 为什么要用等价类划分法? ●从大量数据中划分范围(等价类),然后从每…...

多线程、多进程,还是异步?-- Python 并发 API 如何选择

如何选择正确的 Python 并发 API模块 &#xff1f; Python 标准库提供了三种并发 API &#xff0c; 如何知道你的项目应该使用哪个 API&#xff1f; 在本教程将带逐步了解各API的特性、区别以及各自应用场景&#xff0c;指导你选择最合适的并发 API。 多线程、多进程&#xff0…...

汽车服务管理系统 _od8kr

TOC springboot580汽车服务管理系统 _od8kr--论文 系统概述 该系统由个人管理员和员工管理&#xff0c;用户三部分组成。其中&#xff1a;用户进入系统首页可以实现首页&#xff0c;热销汽车&#xff0c;汽车配件&#xff0c;汽车资讯&#xff0c;后台管理&#xff0c;在线客…...

带你玩转小程序推广,实现短链接一键跳转

不知道各位有没有想过&#xff0c;短链接直接跳转到微信小程序到底该怎么操作呢&#xff1f;掌握这个小技能&#xff0c;能让你的推广效率大幅提升哦。今天就给大家分享一个全新方法&#xff0c;教你如何从短链接直接跳转到微信小程序&#xff0c;实现高效的一键式跨越。 一、…...

OpenDDS的Rtps_Udp传输协议可靠性QoS收发基本流程

OpenDDS中,实现了Rtps_Udp传输协议(非纯udp)的可靠性传输。传输的线程包括: 1)发送方线程主要线程和定时器 《1》应用线程 《2》网络异步发送线程 《3》Heartbeat定时器 《4》Nak_response定时器 2)接收方主要线程和定时器 《1》网络异步接收线程 《2》heartbeat_respons…...

体育数据API纳米奥运会数据API:高阶数据包接口文档API示例⑦

纳米体育数据的数据接口通过JSON拉流方式获取200多个国家的体育赛事实时数据或历史数据的编程接口&#xff0c;无请求次数限制&#xff0c;可按需购买&#xff0c;接口稳定高效&#xff1b;覆盖项目包括足球、篮球、网球、电子竞技、奥运等专题、数据内容。 纳米数据API2.0版本…...

【中项第三版】系统集成项目管理工程师 | 第 15 章 组织保障

前言 本章的知识点预计上午会考1-2分&#xff0c;下午可能会考&#xff0c;一般与其他管理领域进行结合考查。学习要以教材为主。 目录 15.1 信息和文档管理 15.1.1 信息和文档 15.1.2 信息&#xff08;文档&#xff09;管理规则和方法 15.2 配置管理 15.2.1 基本概念 …...

数据结构——顺序栈和链式栈

目录 引言 栈的定义 栈的分类 栈的功能 栈的声明 1.顺序栈 2.链式栈 栈的功能实现 1.栈的初始化 (1)顺序栈 (2)链式栈 (3)复杂度分析 2.判断栈是否为空 (1)顺序栈 (2)链式栈 (3)复杂度分析 3.返回栈顶元素 (1)顺序栈 (2)链式栈 (3)复杂度分析 4.返回栈的大…...

PHP轻创推客集淘客地推任务平台于一体的综合营销平台系统源码

&#x1f680;轻创推客&#xff0c;营销新纪元 —— 集淘客与地推任务于一体的全能平台&#x1f310; &#x1f308;【开篇&#xff1a;营销新潮流&#xff0c;轻创推客引领未来】 在瞬息万变的营销世界里&#xff0c;你还在为寻找高效、全面的营销渠道而烦恼吗&#xff1f;&…...

three.js实现 加载3dtiles ,瓦片 ,倾斜摄影,功能

预览&#xff1a;https://z2586300277.github.io/three-cesium-examples/#/codeMirror?navigationThreeJS&classifyexpand&idloadTiles 部署站点预览&#xff1a;http://threehub.cn/ 开源地址&#xff1a;https://z2586300277.github.io/three-cesium-examples/#/e…...

Qt QTextEdit调用append数据重复的问题

使用QTextEdit写了个串口工具&#xff0c; 当串口有数据时通过一个signal传给slot&#xff0c;在 slot中调用QTextEdit的append(text)来增量显示串口数据&#xff0c;当串口关闭时调用clear()来清空显示。 结果发现append调用后显示的数据会有重复。 分析 分析代码&#xff0…...

数学基础(二)

一、导数 导数计算&#xff1a; 偏导数&#xff1a; 方向导数&#xff1a; 梯度&#xff1a; 函数在某点的梯度是一个向量&#xff0c;它的方向余方向导数最大值取得的方向一致。其大小正好是最大的方向导数 二、微积分 面积由来&#xff1a; 切线&#xff1a; 定积分&#x…...

Java设计模式原则及中介者模式研究

在软件开发过程中&#xff0c;设计模式作为解决常见设计问题的有效工具&#xff0c;对于提升代码质量、促进团队协作具有重要意义。本文系统地阐述了Java设计模式的六大基本原则——单一职责原则、开放封闭原则、里氏替换原则、依赖倒置原则、接口隔离原则以及迪米特法则&#…...

logstash入门学习

1、入门示例 1.1、安装 Redhat 平台 rpm --import http://packages.elasticsearch.org/GPG-KEY-elasticsearch cat > /etc/yum.repos.d/logstash.repo <<EOF [logstash-5.0] namelogstash repository for 5.0.x packages baseurlhttp://packages.elasticsearch.org…...

【代码】Swan-Transformer 代码详解(待完成)

1. 局部注意力 Window Attention (W-MSA Module) class WindowAttention(nn.Module):r""" Window based multi-head self attention (W-MSA) module with relative position bias.It supports both of shifted and non-shifted window.Args:dim (int): Number…...

iframe.contentDocument 和document.documentElement的区别

iframe.contentDocument 和 document.documentElement 是用于访问不同内容的两个不同的对象或属性。 1. iframe.contentDocument 内容: iframe.contentDocument 代表的是 <iframe> 元素所嵌入的文档的 Document 对象。它允许你访问和操作嵌入的文档&#xff08;即 ifram…...

计算机操作员试题(中篇)

计算机操作员试题(中篇) 335.在 Excel中,把鼠标指向被选中单元格边框,当指变成箭头时,拖动鼠标到目标单 元格时,将完成( )操作。 (A)删除 (B)移动 ©自动填充 (D)复制 336.在 Excel 工作表的单元格中,如想输入数字字符串 070615 (例如学号),则应输 入()。 (A) 0007…...

车规级MCU「换道」竞赛

汽车芯片&#xff0c;尤其是MCU市场正在进入拐点期。 本周&#xff0c;总部位于荷兰的汽车芯片制造商—恩智浦&#xff08;NXP&#xff09;半导体总裁兼首席执行官Kurt Sievers在公司第二季度财报电话会议上告诉投资者&#xff0c;由于汽车需求停滞不前&#xff0c;该公司正在努…...

数学生物学-2-离散时间模型(Discrete Time Models)

上一篇介绍了一个指数增长模型。然而&#xff0c;我们也看到&#xff0c;在现实情况下&#xff0c;细菌培养的增长是在离散的时间&#xff08;在这种情况下是小时&#xff09;进行测量的&#xff0c;种群并没有无限增长&#xff0c;而是趋于以S形曲线趋于平稳&#xff0c;称为“…...

免费开源!AI视频自动剪辑已成现实!效率提升80%,打工人福音!(附详细教程)

大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 想象一下&#xff0c;假设老板给你布置了一项任务&#xff1a…...

NtripShare全站仪自动化监测之气象改正

最近有幸和自动化监测领域权威专家进行交流&#xff0c;讨论到全站仪气象改正的问题&#xff0c;因为有些观点与专家不太一致&#xff0c;所以再次温习了一下全站仪气象改正的技术细节。 气象改正的概念 全站仪一般利用光波进行测距&#xff0c;首先仪器会处理测距光波的相位漂…...

【人工智能】项目案例分析:使用自动编码器进行信用卡欺诈检测

一、项目背景 信用卡欺诈是金融行业面临的一个重要问题&#xff0c;快速且准确的欺诈检测对于保护消费者和金融机构的利益至关重要。本项目旨在通过利用自动编码器&#xff08;Autoencoder&#xff09;这一无监督学习算法&#xff0c;来检测信用卡交易中的欺诈行为&#xff0c…...

【工控】线扫相机小结

背景简介 我目前接触到的线扫相机有两种形式: 无采集卡,数据通过网线传输。 配备采集卡,使用PCIe接口。 第一种形式的数据通过网线传输,速度较慢,因此扫描和生成图像的速度都较慢,参数设置主要集中在相机本身。第二种形式的相机配备采集卡,通常速度更快,但由于相机和…...

将Web应用部署到Tomcat根目录的三种方法

将应用部署到Tomcat根目录的三种方法 将应用部署到Tomcat根目录的目的是可以通过"http://[ip]:[port]"直接访问应用&#xff0c;而不是使用"http://[ip]:[port]/[appName]"上下文路径进行访问。 方法一&#xff1a;&#xff08;最简单直接的方法&#xff0…...

工业和信息化部教育与考试中心计算机相关专业介绍

国家工信部的认证证书在行业内享有较高声誉。 此外&#xff0c;还设有专门的工业和信息化技术技能人才数据库查询服务&#xff0c;进一步方便了个人和企业对相关职业能力证书的查询需求。 序号 专业工种 级别 备注 1 JAVA程序员 初级 职业技术 2 电子…...

第二证券:生物天然气线上交易达成 创新探索互联互通、气证合一

8月20日&#xff0c;上海石油天然气生意中心在国内立异推出生物天然气线上生意。当日&#xff0c;绿气新动力&#xff08;北京&#xff09;有限公司&#xff08;简称“绿气新动力”&#xff09;挂单的1500万立方米生物天然气被百事食物&#xff08;我国&#xff09;有限公司&am…...

重磅!RISC-V+OpenHarmony平板电脑发布

仟江水商业电讯&#xff08;8月18日 北京 委托发布&#xff09;RISC-V作为历史上全球发展速度最快、创新最为活跃的开放指令架构&#xff0c;正在不断拓展高性能计算领域的边界。OpenHarmony是由开放原子开源基金会孵化并运营的开源项目&#xff0c;已成为发展速度最快的智能终…...

网站建设 办公系统/seo还有前景吗

知识产权保护是一个很大的概念&#xff0c;包括各种数据、音视频、图片、模型等等。随着计算机和网络技术的发展&#xff0c; 未来社会各种数据资料将是企事业和国家重要的资产。如果不能很好地做到保护自己的数字资产&#xff0c;将是很大的隐患。关于数字资产的保护行业有一些…...

南宁网站开发企业/宜兴百度推广公司

编者按&#xff1a;本文作者为Alexander Haislip&#xff0c;他是云服务器管理公司ScaleXtreme的市场经理。其代表作有 Essentials of Venture Capital&#xff08;《风险投资概要》&#xff09;。 云的出现确实为科技生活带来了很多便利&#xff0c;但随着使用时间越来越多&a…...

丰台网站建设报价/新手怎么学电商运营

CPU 型号的含义 首先介绍 4 个数字的含义&#xff08;以 i7-3540M&#xff09; 第一位 3540M 中的 "3"代表&#xff1a;代&#xff0c; 3 表示第三代 第二位 3540M 中的 "5"代表&#xff1a;代数相同情况下的性能档次 第三位&#xff08;定位很混乱&#x…...

建建建设网站公司电话号码/开发网站建设公司

常用控件和类的使用 Visual Studio.Net(简称VS.Net)使用控件(组件)设计Windows应用程序。将VS.Net工具箱窗口中的控件放到窗体中&#xff0c;使用属性窗口改变控件属性&#xff0c;或在程序中用语句修改控件属性&#xff0c;设计应用程序界面&#xff0c;为控件增加事件函数&am…...

萧山做网站哪里找/百度广告联盟价格

史前时期 20 世纪 60 年代,美国国防部高等研究计划署(ARPA)建立了 ARPA 网,它有四个分布在各地的节点,被认为是如今互联网的“始祖”。 然后在 70 年代,基于对 ARPA 网的实践和思考,研究人员发明出了著名的 TCP/IP 协议。由于具有良好的分层结构和稳定的性能,TCP/IP …...

wordpress 如何安装教程视频/关闭站长工具seo综合查询

在项目开发过程中&#xff0c;我们难免会用到自己去制作自定义的VIEW控件&#xff0c;之后我们别的项目如果需要的话就直接将其复制到对应的项目中使用&#xff0c;虽说这么做是一个解决问题的方法&#xff0c;但毕竟不是很好。 原因是&#xff0c;当我们项目积累越来越多&…...