了解索引对表的影响以及如何分析查询计划,在MySQL中进行SQL查询性能调优

如何设置MySQL数据库和编写存储过程进行批量数据插入。通过理解这些概念,您将能够优化SQL查询并提高数据库的响应时间。

在本文中,我们将学习如何通过对表列进行索引来提高SQL查询的快速响应时间。我们将涵盖安装MySQL、创建存储过程、分析查询以及了解索引的影响的步骤。

我在Ubuntu上使用了MySQL 8版本。同时,我使用Dbeavor工具作为MySQL客户端连接到MySQL服务器。让我们一起学习吧。

我在演示中使用了MySQL,然而,在所有其他数据库中,概念是相同的。

MySQL,sql优化

1.下面是我们安装MySQL并使用root用户访问的方法。

这个MySQL实例仅用于测试,因此我使用了一个简单的密码

# 安装
$ sudo apt install mysql-server
# 启动服务
$ sudo systemctl start mysql.service
#开始使用服务
$ sudo mysql
# 设置密码规则
mysql> SET GLOBAL validate_password.policy = 0;
# 设置一个简单的密码
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
# 退出
mysql> exit
# 试试重新登录
$ mysql -uroot -ppassword

2.创建一个数据库并使用它。

# 创建数据库
mysql> create database testdb;
# 查看数据库
mysql> show databases;
# 使用这个数据库
mysql> use testdb;

3.创建两个表,employee1和employee2。

其中,employee1没有主键,而employee2有主键。

# 创建表 employee1
mysql> CREATE TABLE employee1 (id int,LastName varchar(255),FirstName varchar(255),Address varchar(255),profile varchar(255));
Query OK, 0 rows affected (0.01 sec)
# 创建表 employee2,并且设置一个主键 
mysql> CREATE TABLE employee2 (id int primary key,LastName varchar(255),FirstName varchar(255),Address varchar(255),profile varchar(255));
Query OK, 0 rows affected (0.02 sec
# 查看表
mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| employee1        |
| employee2        |
+------------------+
2 rows in set (0.00 sec)

4. 检查每个表的索引

我们会发现employee2表已经在id列上有一个索引,因为它是主键。

mysql> SHOW INDEXES FROM employee1 \G;
Empty set (0.00 sec)

ERROR: 
No query specified

mysql> SHOW INDEXES FROM employee2 \G;
*************************** 1. row ***************************
        Table: employee2
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: 
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: YES
   Expression: NULL
1 row in set (0.00 sec)

ERROR: 
No query specified

5. 创建一个存储过程来批量插入数据到这两个表中。

我们将在每个表中插入20000条记录。然后可以使用CALL procedure-name命令调用存储过程。

mysql> 

CREATE PROCEDURE testdb.BulkInsert()
BEGIN
		DECLARE i INT DEFAULT 1;
truncate table employee1;
truncate table employee2;
WHILE (i <= 20000) DO
    INSERT INTO testdb.employee1 (id, FirstName, Address) VALUES(i, CONCAT("user","-",i), CONCAT("address","-",i));
    INSERT INTO testdb.employee2 (id,FirstName, Address) VALUES(i,CONCAT("user","-",i), CONCAT("address","-",i));    
   SET i = i+1;
END WHILE;
END

mysql> CALL testdb.BulkInsert() ;

mysql> SELECT COUNT(*) from employee1 e ;
COUNT(*)|
--------+
    20000|
    

mysql> SELECT COUNT(*) from employee2 e ;
COUNT(*)|
--------+
    20000|

6. 选择任意随机id的记录

我们会发现employee1表的响应速度较慢,因为它没有任何索引。

mysql> select * from employee2 where id = 15433;
+-------+----------+------------+---------------+---------+
| id    | LastName | FirstName  | Address       | profile |
+-------+----------+------------+---------------+---------+
| 15433 | NULL     | user-15433 | address-15433 | NULL    |
+-------+----------+------------+---------------+---------+
1 row in set (0.00 sec)

mysql> select * from employee1 where id = 15433;
+-------+----------+------------+---------------+---------+
| id    | LastName | FirstName  | Address       | profile |
+-------+----------+------------+---------------+---------+
| 15433 | NULL     | user-15433 | address-15433 | NULL    |
+-------+----------+------------+---------------+---------+
1 row in set (0.03 sec)

mysql> select * from employee1 where id = 19728;
+-------+----------+------------+---------------+---------+
| id    | LastName | FirstName  | Address       | profile |
+-------+----------+------------+---------------+---------+
| 19728 | NULL     | user-19728 | address-19728 | NULL    |
+-------+----------+------------+---------------+---------+
1 row in set (0.03 sec)

mysql> select * from employee2 where id = 19728;
+-------+----------+------------+---------------+---------+
| id    | LastName | FirstName  | Address       | profile |
+-------+----------+------------+---------------+---------+
| 19728 | NULL     | user-19728 | address-19728 | NULL    |
+-------+----------+------------+---------------+---------+
1 row in set (0.00 sec)

mysql> select * from employee1 where id = 3456;
+------+----------+-----------+--------------+---------+
| id   | LastName | FirstName | Address      | profile |
+------+----------+-----------+--------------+---------+
| 3456 | NULL     | user-3456 | address-3456 | NULL    |
+------+----------+-----------+--------------+---------+
1 row in set (0.04 sec)

mysql> select * from employee2 where id = 3456;
+------+----------+-----------+--------------+---------+
| id   | LastName | FirstName | Address      | profile |
+------+----------+-----------+--------------+---------+
| 3456 | NULL     | user-3456 | address-3456 | NULL    |
+------+----------+-----------+--------------+---------+
1 row in set (0.00 sec)

7. 检查命令EXPLAIN ANALYZE的输出。

该命令实际执行查询,并对查询进行规划、监控并计算在执行计划的各个点处所花费的时间和行数。

mysql> explain analyze select * from employee1 where id = 3456;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                               |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Filter: (employee1.id = 3456)  (cost=1989 rows=1965) (actual time=5.24..29.3 rows=1 loops=1)
    -> Table scan on employee1  (cost=1989 rows=19651) (actual time=0.0504..27.3 rows=20000 loops=1)
 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.03 sec)

#从ChatGPT的详细解释中可以得到以下信息:

filter: (employee1.id = 3456):这表示在"employee1"表上执行了一个过滤操作,只会选择"id"列值为3456的行。

(cost=1989 rows=1965) (actual time=5.3..31.9 rows=1 loops=1):这部分提供了关于查询执行的一些性能相关信息:

cost=1989:它代表整个查询执行的成本估算。成本是度量执行查询所需的计算工作量的相对指标。

rows=1965:它表示在查询的这一部分中将处理的预估行数。

actual time=5.3..31.9:这显示了查询执行这一部分的实际时间,以毫秒为单位进行测量。

rows=1 loops=1:表示该查询的这一部分在循环中执行的次数。
-> Table scan on employee1 (cost=1989 rows=19651) (actual time=0.034..29.7 rows=20000 loops=1):这部分显示正在"employee1"表上执行表扫描操作:

Table scan:这意味着数据库正在扫描整个"employee1"表,以查找与过滤条件匹配的行。

cost=1989:此表扫描操作的成本估算。

rows=19651:在"employee1"表中的预估行数。

actual time=0.034..29.7:表扫描操作的实际执行时间,以毫秒为单位进行测量。

rows=20000 loops=1:此表扫描操作在循环中执行的次数。

总体而言,这个查询计划表明数据库正在执行一个查询,将"employee1"表进行筛选,仅返回"id"列等于3456的行。
表扫描操作读取了共计20,000行以找到匹配的行,并且估算成本为1989个单位。
实际执行时间为5.3至31.9毫秒,取决于符合过滤条件的行数。

在这里,我们发现对于employee1,执行了一次表扫描,这意味着要扫描或搜索整个表来获取结果。我们也称之为对表进行全面扫描。

8. 对于employee2表,我们发现只搜索并获取了一行结果。

因此,如果表中有很多记录,我们将观察到SQL查询响应时间的明显改善。

mysql> explain analyze select * from employee2 where id = 3456;
+---------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                           |
+---------------------------------------------------------------------------------------------------+
| -> Rows fetched before execution  (cost=0..0 rows=1) (actual time=110e-6..190e-6 rows=1 loops=1)
 |
+---------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

#根据ChatGPT对这个查询计划的解释:

在执行之前获取的行:这部分表示数据库在执行主查询之前获取了一些数据。

(cost=0..0 rows=1):这个操作的成本估算为0个单位,它预期只获取一行。

(actual time=110e-6..190e-6 rows=1 loops=1):这提供了数据获取操作的实际时间:

actual time=110e-6..190e-6:数据获取操作的实际时间范围,以微秒(µs)为单位进行测量。

rows=1:获取的行数。

loops=1:此数据获取操作在循环中执行的次数。

总体而言,查询计划的这部分表示数据库在执行主查询之前获取了一行数据。这个数据获取操作的实际时间范围为110到190微秒。这个初步的数据获取可能与获取一些执行主查询所需的关键信息或参数有关。

9. 让我们分析当我们在两个表的非索引列FirstName上搜索记录时的查询计划。

从输出中,我们发现执行了表扫描来搜索记录,这需要相当长的时间来获取数据。

mysql> explain analyze select * from employee2 where FirstName = 'user-13456';
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                            |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Filter: (employee2.FirstName = 'user-13456')  (cost=2036 rows=2012) (actual time=15.7..24 rows=1 loops=1)
    -> Table scan on employee2  (cost=2036 rows=20115) (actual time=0.0733..17.8 rows=20000 loops=1)
 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.02 sec)

mysql> explain analyze select * from employee1 where FirstName = 'user-13456';
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                              |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Filter: (employee1.FirstName = 'user-13456')  (cost=1989 rows=1965) (actual time=23.7..35.2 rows=1 loops=1)
    -> Table scan on employee1  (cost=1989 rows=19651) (actual time=0.0439..28.9 rows=20000 loops=1)
 |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.03 sec)

10. 在employee1表的FirstName列上创建一个索引

mysql> CREATE INDEX index1 ON employee1 (FirstName);
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show indexes from employee1 \G;
*************************** 1. row ***************************
        Table: employee1
   Non_unique: 1
     Key_name: index1
 Seq_in_index: 1
  Column_name: FirstName
    Collation: A
  Cardinality: 19651
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: YES
   Expression: NULL
1 row in set (0.01 sec)

ERROR: 
No query specified

11. 再次检查两个表在搜索FirstName列的单条记录时的查询计划。

我们发现employee1快速提供响应,只有1行要搜索,并且在使用FirstName列上的索引时,在employee1表上执行了索引查找。但对于employee2,响应时间较长,并且要搜索所有20000行才能获得响应。

mysql> explain analyze select * from employee1 where FirstName = 'user-13456';
+-------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                             |
+-------------------------------------------------------------------------------------------------------------------------------------+
| -> Index lookup on employee1 using index1 (FirstName='user-13456')  (cost=0.35 rows=1) (actual time=0.0594..0.0669 rows=1 loops=1)
 |
+-------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


mysql> explain analyze select * from employee2 where FirstName = 'user-13456';
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                             |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Filter: (employee2.FirstName = 'user-13456')  (cost=2036 rows=2012) (actual time=15.7..23.5 rows=1 loops=1)
    -> Table scan on employee2  (cost=2036 rows=20115) (actual time=0.075..17.5 rows=20000 loops=1)
 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.02 sec)

就是这样,同学们。本文将帮助我们理解索引对表的影响,如何使用"explain analyze"命令分析查询。还有关于如何设置MySQL和如何编写用于批量插入的存储过程的学习内容。文章来源地址https://www.toymoban.com/diary/sql/686.html


到此这篇关于了解索引对表的影响以及如何分析查询计划,在MySQL中进行SQL查询性能调优的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/diary/sql/686.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用
MS SQL Server 数据库数据丢失,意外损坏,如何在简单的步骤中恢复数据库
上一篇 2024年01月11日 22:59
使用Schema类型在Java中创建SQL查询 - Kilo框架介绍
下一篇 2024年01月11日 23:58

相关文章

  • 【flink番外篇】9、Flink Table API 支持的操作示例(4)- Table API 对表的查询、过滤操作

    一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。 3、

    2024年01月17日
    浏览(27)
  • 如何查询oracle中一个表的一个字段是否加了索引

    要查询Oracle数据库中一个表的一个字段是否已添加索引,可以使用以下SQL语句: 在上面的SQL语句中,将your_table_name替换为你要查询的表的名称,将your_column_name替换为你要查询的字段的名称。 这个查询语句会返回与指定表和字段关联的所有索引的名称和列名称。如果返回结果

    2024年04月16日
    浏览(20)
  • 可抓取性和可索引性:它们是什么以及如何影响搜索引擎优化

    网页的可抓取性是指搜索引擎(如谷歌)发现网页的难易程度。 谷歌发现网页的过程称为爬行。它使用称为网络爬虫(也称为机器人或蜘蛛)的计算机程序。这些程序会跟踪网页之间的链接,以发现新的或更新的网页。 索引通常是在爬行之后进行的。 网页的可索引性意味着

    2024年02月01日
    浏览(23)
  • 【postgresql 基础入门】表的操作,表结构查看、修改字段类型、增加删除字段、重命名表,对表的操作总是比别人棋高一着

    ​ 专栏内容 : postgresql内核源码分析 手写数据库toadb 并发编程 ​ 开源贡献 : toadb开源库 个人主页 :我的主页 管理社区 :开源数据库 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 入门准备 postgrersql基础架构 快速使用 初始化集群 数据库服务管理 psql客户

    2024年02月08日
    浏览(16)
  • 外文期刊影响因子去哪里查询,如何查询

    期刊影响因子(Impact factor,IF),是代表期刊影响大小的一项定量指标。也就是某刊平均每篇论文的被引用数,它实际上是某刊在某年被全部源刊物引证该刊前两年发表论文的次数,与该刊前两年所发表的全部源论文数之比。那么,去哪里查询以及怎么查询期刊的影响因子呢?

    2024年02月15日
    浏览(16)
  • 浅谈SQL Server索引视图(物化视图)以及索引视图与查询重写

    目录 (一)前言 (二)正文 1. 物化视图(索引视图)与查询重写的基本概念 2. 创建测试环境 (1)建表 (2)写数据 3. 索引视图创建 (1)创建语法 (2)为索引视图创建索引  4. 查询重写 5. 为什么查询会被重写  6. 索引视图什么时候更新 7. 改变基于视图的查询 之前做

    2024年02月05日
    浏览(39)
  • Java操作elasticSearch复杂查询以及解析数据以及索引保存数据

    说明:基于银行测试库的操作 es的银行测试库,看一个Kibana操作 然后用java检索解析这个数据 聚合搜索 address 中包含 mill 的所有人的年龄分布以及平均薪资 以下是分解思路实现步骤: #聚合搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄 GET bank/_search { “query”:{ “

    2024年02月10日
    浏览(23)
  • 二、SQL,如何实现表的创建和查询

    示例: 示例:  

    2024年02月12日
    浏览(12)
  • C语言中线性表的合并&有序表的合并以及案例分析和实现

    **线性列表合并:**   案例分析: 要合并两个线性列表,我们考虑以下情况:   1. 两个列表都是空的:在这种情况下,合并的列表也将是空的。 2. 一个列表是空的:如果其中一个列表是空的,则合并的列表将是非空列表本身。 3. 两个列表都是非空的:在这种情况下,我们同

    2024年02月01日
    浏览(26)
  • 如何使用索引加速 SQL 查询 [Python 版]

    推荐:使用 NSDT场景编辑器助你快速搭建可二次编辑器的3D应用场景 假设您正在筛选一本书的页面。而且您希望更快地找到所需的信息。你是怎么做到的?好吧,您可能会查找术语索引,然后跳转到引用特定术语的页面。SQL 中的索引的工作方式与书籍 中的索引 类似。 在大多

    2024年02月13日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包