Mysql--实战篇--SQL优化(查询优化器,常用的SQL优化方法,执行计划EXPLAIN,Mysql性能调优,慢日志开启和分析等)

news2025/1/16 17:00:34

一、查询优化

1、查询优化器 (Query Optimizer)

MySQL查询优化器(Query Optimizer)是MySQL数据库管理系统中的一个关键组件,负责分析和选择最有效的执行计划来执行SQL查询。查询优化器的目标是尽可能减少查询的执行时间和资源消耗,从而提高查询性能。

查询语句不同关键字(where、jion、limit、group by、having等)执行时,访问的先后顺序?
查询中用到的关键词主要包含六个,并且他们的顺序依次为
select–from–where–group by–having–order by

(1)、查询优化器的工作原理

1、解析查询:将SQL语句解析为内部表示形式(通常是抽象语法树,AST),并进行语法和语义检查。
2、生成可能的执行计划:根据表结构、索引、统计信息等,生成多个可能的查询执行计划。
3、评估执行成本:为每个可能的执行计划估算其执行成本(如I/O操作次数、CPU使用时间等),并选择成本最低的执行计划。
4、执行查询:按照选定的执行计划执行查询,并返回结果。

(2)、查询优化器的工作流程
1、解析查询

当用户提交一条SQL查询时,MySQL首先会通过解析器将SQL语句转换为内部表示形式(抽象语法树)。解析器会检查SQL语句的语法是否正确,并确保查询中引用的表、列和函数都存在且有效。
例如,假设我们有以下查询:

SELECT name, age FROM users WHERE age > 30;

解析器会将这条查询解析为一个内部表示形式,标识出SELECT、FROM、WHERE等关键字,以及它们对应的表名、列名和条件表达式。

2、生成可能的执行计划

在解析完成后,查询优化器会生成多个可能的执行计划。执行计划描述了如何访问表中的数据、如何应用过滤条件、如何连接多个表等。

查询优化器会考虑以下因素来生成不同的执行计划:

  • 表的访问顺序:如果查询涉及多个表,优化器会尝试不同的表连接顺序,以找到最优的顺序。
  • 索引的选择:优化器会评估表上的所有可用索引,并决定是否使用某个索引来加速查询。
  • 连接方法:对于多表查询,优化器会选择合适的连接方法(如嵌套循环连接、哈希连接、合并连接等)。
  • 聚合和排序:如果查询包含GROUP BY或ORDER BY子句,优化器会决定如何高效地执行这些操作。

示例:

SELECT u.name, o.order_date 
FROM users u 
JOIN orders o ON u.user_id = o.user_id 
WHERE u.age > 30;

对以上的sql,优化器可能会生成以下几种执行计划:

  • 先扫描users表,找到所有age > 30的用户,然后通过user_id索引查找对应的orders表记录。
  • 先扫描orders表,找到所有订单,然后通过user_id索引查找对应的users表记录,并应用age > 30的过滤条件。
3、评估执行成本

为了选择最优的执行计划,查询优化器会为每个可能的执行计划估算其执行成本。

成本评估基于以下因素:

  • I/O成本:读取磁盘页面的数量。I/O操作通常是最耗时的部分,因此优化器会尽量减少磁盘I/O。
  • CPU成本:CPU使用的时间。包括比较、计算、排序等操作的开销。
  • 内存使用:查询执行过程中需要的内存资源。过多的内存使用可能导致缓存失效或交换到磁盘,影响性能。
  • 表的大小和索引的覆盖性:优化器会考虑表的行数、索引的覆盖情况等因素。如果索引能够覆盖查询所需的所有列,则可以直接从索引中获取数据,而不需要访问表的数据页。
  • 统计信息:优化器会使用表和索引的统计信息(如行数、列的唯一值数量、索引的选择性等)来估计查询的执行成本。统计信息越准确,优化器的选择就越合理。

例如,假设users表有100万行数据,而orders表有500万行数据。优化器会根据统计信息估算不同执行计划的I/O和CPU成本,并选择成本最低的计划。

4、执行查询

一旦选择了最优的执行计划,MySQL就会按照该计划执行查询,并返回结果。查询优化器还会将执行计划缓存起来,以便在后续相同的查询中重用,避免重复优化。

(3)、查询优化器的关键技术
1、索引选择

索引是查询优化器最重要的工具之一。优化器会根据查询条件、表结构和索引的覆盖性,选择最适合的索引。

常见的索引类型包括:

  • B+树索引:适用于范围查询、精确匹配和排序操作。
  • 哈希索引:适用于精确匹配查询,但不支持范围查询。
  • 全文索引:适用于全文搜索。
  • 空间索引:适用于地理空间数据的查询。

优化器会根据查询的条件和表的统计信息,评估每个索引的选择性和覆盖性。例如,如果查询只涉及索引中的列,优化器可能会选择使用覆盖索引(Covering Index),以避免额外的表扫描。

2、连接优化

对于多表查询,优化器会决定如何连接这些表。

常见的连接方法包括:

  • 嵌套循环连接(Nested Loop Join):逐行扫描外层表,然后在内层表中查找匹配的记录。适用于小表或有索引的表。
  • 哈希连接(Hash Join):将一个表的数据加载到内存中的哈希表中,然后扫描另一个表并与哈希表进行匹配。适用于大表之间的连接。
  • 合并连接(Merge Join):适用于两个已经排序的表,通过合并两个有序的结果集来完成连接。适用于带有ORDER BY或GROUP BY的查询。

优化器会根据表的大小、索引的存在与否以及查询条件,选择最适合的连接方法。

3、子查询优化

MySQL查询优化器还支持多种子查询优化技术,以提高子查询的执行效率。

常见的子查询优化策略包括:

  • 子查询展开(Subquery Unnesting):将子查询转换为等价的连接查询,以减少嵌套层次。
  • 物化子查询(Materialization):将子查询的结果物化为临时表,避免多次执行子查询。
  • 半连接优化(Semi-Join Optimization):对于EXISTS或IN子查询,优化器会将其转换为半连接操作,减少不必要的数据扫描。
4、并行查询

在MySQL 8.0及更高版本中,查询优化器支持并行查询执行。对于大型查询,优化器可以将查询分解为多个并行任务,利用多核CPU提高查询性能。

并行查询适用于以下场景:

  • 大规模表扫描
  • 复杂的聚合操作
  • 多表连接

并行查询的启用可以通过配置参数innodb_parallel_read_threads来控制。

5、查询缓存

虽然MySQL 8.0及更高版本已经移除了传统的查询缓存(Query Cache),但优化器仍然会缓存执行计划。查询缓存的作用是存储之前执行过的查询结果,以便在相同查询再次执行时直接返回缓存的结果,而不必重新执行查询。虽然查询缓存可以提高某些查询的性能,但它也可能导致一致性问题,并且在高并发场景下效果不佳。

(4)、如何查看查询优化器的行为

MySQL提供了多种工具和命令,帮助你查看查询优化器的行为和执行计划。以下是常用的工具和命令:

1、EXPLAIN

EXPLAIN是最常用的工具,用于显示查询的执行计划。它可以帮助你了解优化器如何选择表、索引和连接方法。

sql示例:

EXPLAIN SELECT name, age FROM users WHERE age > 30;

EXPLAIN的输出包括以下列:

  • id:查询的标识符,标识查询的顺序。
  • select_type:查询的类型(如简单查询、子查询、联合查询等)。
  • table:当前操作的表。
  • partitions:涉及的分区(如果有分区表)。
  • type:访问类型(如ALL、index、range、ref等)。
  • possible_keys:可能使用的索引。
  • key:实际使用的索引。
  • key_len:索引的长度。
  • ref:与索引比较的列或常量。
  • rows:估计需要扫描的行数。
  • filtered:根据条件过滤后剩余的行数百分比。
  • Extra:额外的信息,如是否使用临时表、是否进行排序等。
2、SHOW WARNINGS

SHOW WARNINGS可以显示查询优化器在执行过程中生成的警告信息。这些警告信息可以帮助你发现潜在的问题,如未使用的索引、隐式类型转换等。
sql示例:

SHOW WARNINGS;
3、Optimizer_Trace

Optimizer_Trace是MySQL 5.6及更高版本中引入的功能,提供了更详细的查询优化过程跟踪。你可以通过设置系统变量optimizer_trace来启用此功能,并查看优化器的决策过程。
sql示例:

SET optimizer_trace='enabled=on';
SELECT name, age FROM users WHERE age > 30;
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

运行结果:
在这里插入图片描述

4、Performance Schema

Performance Schema是MySQL的性能监控工具,提供了对查询执行的详细统计信息。你可以使用Performance Schema来跟踪查询的执行时间、I/O操作、锁争用等情况。
sql示例:

SELECT * FROM performance_schema.events_statements_current;

运行结果:
在这里插入图片描述

2、常见SQL优化手段

SQL查询优化是提高数据库性能的关键步骤,尤其是在处理大规模数据时。通过优化查询,可以减少I/O操作、降低CPU使用率、减少内存占用,并最终提升系统的响应速度。以下是常见的SQL优化手段,涵盖了从查询编写、索引设计到数据库配置等多个方面。

(1)、创建合适的索引

索引是SQL查询优化中最重要且最有效的工具之一。合理的索引设计可以显著提高查询性能,尤其是对于大表和复杂的查询。以下是一些创建索引的最佳实践:

1、覆盖索引(Covering Index)

覆盖索引是指索引中包含了查询所需的所有列,这样查询可以直接从索引中获取数据,而不需要访问表的数据页。这可以显著减少I/O操作。

示例:
假设我们有一个查询SELECT name, age FROM users WHERE age > 30,可以在age和name上创建组合索引,使其成为覆盖索引。
sql示例:

CREATE INDEX idx_age_name ON users (age, name);
2、组合索引(Composite Index)

组合索引是由多个列组成的索引。在创建组合索引时,应该将最常用的查询条件列放在前面,以提高索引的选择性。

示例:
对于查询SELECT * FROM orders WHERE customer_id = 1 AND order_date > ‘2023-01-01’,可以在customer_id和order_date上创建组合索引。
sql示例:

CREATE INDEX idx_customer_order_date ON orders (customer_id, order_date);
3、前缀索引(Prefix Index)

对于长字符串列(如VARCHAR),可以创建前缀索引,只索引字符串的前几个字符。这可以减少索引的大小,同时仍然提供良好的查询性能。

示例:
假设我们有一个email列,可以创建一个前缀索引来索引前20个字符。
sql示例:

CREATE INDEX idx_email_prefix ON users (email(20));
4、唯一索引(Unique Index)

如果某个列需要保证唯一性,建议使用唯一索引。唯一索引不仅可以确保数据的完整性,还可以加速基于该列的查询。

示例:
对于user_id列,可以创建唯一索引。
sql示例:

CREATE UNIQUE INDEX idx_user_id ON users (user_id);
5、避免过度索引

虽然索引可以提高查询性能,但过多的索引会增加插入、更新和删除操作的开销。因此,应该只在常用的查询条件上创建索引,避免为每个列都创建索引。

(2)、优化查询语句

编写高效的SQL查询语句是提高性能的重要手段。以下是一些常见的查询优化技巧:

1、避免使用SELECT *

尽量避免使用 SELECT *,因为它会返回所有列,即使某些列并不需要。这不仅增加了网络传输的数据量,还可能导致不必要的I/O操作。

sql示例:

- 优化前:
SELECT * FROM users WHERE age > 30;
- 优化后:
SELECT id, name, age FROM users WHERE age > 30;
2、使用EXISTS替代IN

在子查询中,EXISTS通常比IN更高效,尤其是在子查询返回大量结果时。EXISTS只需要找到一条匹配的记录即可终止查询,而IN需要遍历整个子查询结果集。

sql示例:

- 优化前:
SELECT * FROM orders WHERE user_id IN (SELECT user_id FROM users WHERE age > 30);
- 优化后:
SELECT * FROM orders o WHERE EXISTS (SELECT 1 FROM users u WHERE u.user_id = o.user_id AND u.age > 30);
3、使用JOIN替代子查询

对于多表查询,尽量使用JOIN代替嵌套子查询。JOIN通常比子查询更高效,因为优化器可以更好地优化连接操作。

sql示例:

- 优化前:
SELECT * FROM orders WHERE user_id IN (SELECT user_id FROM users WHERE age > 30);
- 优化后:
SELECT o.* 
FROM orders o 
JOIN users u ON o.user_id = u.user_id 
WHERE u.age > 30;
4、避免隐式类型转换

隐式类型转换会导致索引失效,因为数据库无法直接使用索引来加速查询。确保查询条件中的列和常量类型一致,避免不必要的类型转换。

sql示例:

- 优化前:
SELECT * FROM users WHERE age = '30';  -- 字符串与整数比较
- 优化后:
SELECT * FROM users WHERE age = 30;  -- 整数与整数比较
5、分页查询优化

对于分页查询,尽量避免使用OFFSET,因为它会导致全表扫描。可以考虑使用主键或唯一列进行分页,或者使用覆盖索引。

sql示例:

- 优化前:
SELECT * FROM users LIMIT 1000 OFFSET 9000;
- 优化后:
SELECT * FROM users WHERE id > 9000 ORDER BY id LIMIT 1000;
6、使用批量操作

在插入、更新或删除大量数据时,尽量使用批量操作,而不是逐行处理。批量操作可以减少与数据库的交互次数,显著提高性能。

sql示例:

- 优化前:
INSERT INTO users (name, age) VALUES ('Alice', 30);
INSERT INTO users (name, age) VALUES ('Bob', 35);
INSERT INTO users (name, age) VALUES ('Charlie', 40);
- 优化后:
INSERT INTO users (name, age) VALUES 
('Alice', 30),
('Bob', 35),
('Charlie', 40);
(3)、优化表结构

合理的表结构设计可以显著提高查询性能。以下是一些建议:

1、选择合适的数据类型

选择合适的数据类型不仅可以节省存储空间,还可以提高查询性能。尽量使用最小的数据类型,避免不必要的复杂类型。

常用类型:

  • 整数类型:根据实际需求选择最小的整数类型(如TINYINT、SMALLINT、INT、BIGINT)。
  • 字符类型:尽量使用VARCHAR而不是TEXT,并且为VARCHAR设置合理的长度限制。
  • 日期和时间类型:使用DATE或DATETIME类型来存储日期和时间,而不是使用字符串。
  • 布尔类型:MySQL没有专门的布尔类型,通常使用TINYINT(1)来表示布尔值(0或1)。
2、使用分区表

对于大型表,可以考虑使用分区表(Partitioning)。分区表可以根据某些条件(如日期、范围、列表等)将数据分散到不同的物理存储区域,从而提高查询性能和管理效率。

示例:
按年份对订单表进行分区。
sql示例:

CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    order_date DATE,
    amount DECIMAL(10, 2)
) PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023)
);
3、垂直拆分表

如果某个表包含大量的列,且某些列很少被查询,可以考虑将表进行垂直拆分。将不常用的列拆分到单独的表中,减少主表的宽度,从而提高查询性能。

示例:
将用户的基本信息和详细信息拆分为两个表。
sql示例:

CREATE TABLE users_basic (
    user_id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100)
);

CREATE TABLE users_detail (
    user_id INT PRIMARY KEY,
    address TEXT,
    phone_number VARCHAR(20),
    FOREIGN KEY (user_id) REFERENCES users_basic(user_id)
);
4、水平拆分表

对于非常大的表,可以考虑进行水平拆分(Sharding)。水平拆分是将表的数据按某种规则(如用户ID、地区等)分布到多个表或多个数据库实例中,以减少单个表的规模。

示例:
按用户ID进行水平拆分。
sql示例:

CREATE TABLE users_0 (
    user_id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100)
);

CREATE TABLE users_1 (
    user_id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100)
);
(4)、优化数据库配置

合理的数据库配置可以显著提高查询性能。以下是一些常见的配置优化建议:

1、调整缓冲区大小

MySQL提供了多种缓冲区来缓存查询结果、索引、表数据等。适当调整这些缓冲区的大小可以提高查询性能。

  • InnoDB缓冲池(innodb_buffer_pool_size):用于缓存InnoDB表的数据和索引。建议将其设置为服务器内存的70%左右。
    sql示例:
SET GLOBAL innodb_buffer_pool_size = 8G;
  • 查询缓存(query_cache_size):MySQL 8.0及更高版本已经移除了传统的查询缓存,但在MySQL 5.x版本中,可以适当调整查询缓存的大小。不过,查询缓存在高并发场景下效果不佳,建议谨慎使用。
    sql示例:
SET GLOBAL query_cache_size = 64M;
2、启用并行查询

在MySQL 8.0及更高版本中,查询优化器支持并行查询执行。对于大型查询,启用并行查询可以利用多核CPU提高查询性能。

  • 启用并行读取线程:
    示例:
SET GLOBAL innodb_parallel_read_threads = 4;
3、调整事务隔离级别

MySQL支持四种事务隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。默认情况下,MySQL使用REPEATABLE READ,但根据应用的需求,可以选择更低的隔离级别来提高并发性能。

  • 设置事务隔离级别:
    sql示例:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
4、禁用不必要的日志

某些日志(如二进制日志、慢查询日志等)会增加I/O开销。如果不需要这些日志,可以禁用它们以提高性能。

  • 禁用二进制日志:
    sql示例:
SET GLOBAL binlog_format = 'OFF';
  • 禁用慢查询日志:
    sql示例:
SET GLOBAL slow_query_log = 'OFF';
(5)、使用查询缓存

虽然MySQL 8.0及更高版本已经移除了传统的查询缓存,但你仍然可以通过其他方式实现类似的效果:

1、使用Redis或Memcached

可以使用Redis或Memcached等内存缓存系统来缓存频繁访问的查询结果。缓存系统可以显著减少数据库的负载,特别是在高并发场景下。

2、使用查询结果缓存

对于一些不经常变化的查询结果,可以考虑将结果缓存到文件或内存中,避免每次都从数据库中读取。

(6)、监控和分析查询性能

定期监控和分析查询性能可以帮助你发现潜在的性能瓶颈,并及时采取优化措施。以下是一些常用的监控和分析工具:

1、EXPLAIN

EXPLAIN是最常用的工具,用于显示查询的执行计划。它可以帮助你了解优化器如何选择表、索引和连接方法。

sql示例:

EXPLAIN SELECT name, age FROM users WHERE age > 30;
2、慢查询日志

慢查询日志记录了执行时间超过指定阈值的查询。通过分析慢查询日志,可以找出需要优化的查询。

  • 启用慢查询日志:
    sql示例:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;  -- 记录执行时间超过1秒的查询为慢查询
3、Performance Schema

Performance Schema是MySQL的性能监控工具,提供了对查询执行的详细统计信息。你可以使用Performance Schema来跟踪查询的执行时间、I/O 操作、锁争用等情况。

sql示例:

SELECT * FROM performance_schema.events_statements_current;
4、Optimizer_Trace

Optimizer Trace提供了详细的查询优化过程跟踪,帮助你了解优化器的决策过程。

  • 启用Optimizer Trace:
    sql示例:
SET optimizer_trace='enabled=on';
SELECT name, age FROM users WHERE age > 30;
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
(7)、SQL查询优化总结

SQL查询优化是一个多方面的过程,涉及到索引设计、查询语句编写、表结构调整、数据库配置等多个方面。通过合理使用索引、优化查询语句、调整表结构和数据库配置,可以显著提高查询性能,减少资源消耗,并最终提升系统的响应速度。

常见SQL优化手段包括:
1、创建合适的索引:使用覆盖索引、组合索引、前缀索引等,确保查询能够高效地使用索引。
2、优化查询语句:避免使用SELECT ,使用EXISTS替代IN,使用JOIN替代子查询,避免隐式类型转换,优化分页查询。
3、优化表结构:选择合适的数据类型,使用分区表、垂直拆分表、水平拆分表等技术。
4、优化数据库配置:调整缓冲区大小、启用并行查询、调整事务隔离级别、禁用不必要的日志。
5、使用查询缓存:使用Redis或Memcached等缓存系统,缓存频繁访问的查询结果。
6、监控和分析查询性能:使用EXPLAIN、慢查询日志、Performance Schema和Optimizer Trace 等工具,监控和分析查询性能。

二、执行计划(EXPLAIN)

EXPLAIN是最常用的工具,用于显示查询的执行计划。它可以帮助你了解优化器如何选择表、索引和连接方法。

我们将使用一个常见的场景:用户订单系统,涉及users和orders两个表。并详细解释EXPLAIN的输出结果。

1、创建测试数据

sql示例:

-- 创建users表
CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100),
    age INT
);

-- 创建 orders 表
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    order_date DATE,
    amount DECIMAL(10, 2),
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

-- 插入测试数据
INSERT INTO users (name, email, age) VALUES 
('Alice', 'alice@example.com', 35),
('Bob', 'bob@example.com', 28),
('Charlie', 'charlie@example.com', 40),
('David', 'david@example.com', 25);

INSERT INTO orders (user_id, order_date, amount) VALUES 
(1, '2023-01-01', 100.00),
(1, '2023-02-01', 200.00),
(2, '2023-03-01', 150.00),
(3, '2023-04-01', 300.00);

2、查看未优化查询的执行计划

sql示例:

EXPLAIN SELECT u.name, o.order_date, o.amount 
FROM users u 
JOIN orders o ON u.user_id = o.user_id 
WHERE u.age > 30;

运行结果:
在这里插入图片描述

3、执行计划解释

1、id列:表示查询的优先级顺序。在这个例子中,id为1,表示这两行优先级一致。
2、select_type列:表示查询的类型。SIMPLE表示这是一个简单的查询,不包含子查询或联合查询。
3、table列:表示当前操作的表。第一个行是users表,第二个行是orders表。
4、partitions列:表示涉及的分区(如果有分区表)。在这个例子中,没有使用分区表,因此该列为NULL。
5、type列:表示访问类型。ALL表示全表扫描,ref表示通过索引进行查找。

  • 对于users表,type为ALL,表示优化器选择了全表扫描,因为没有合适的索引可以使用。
  • 对于orders表,type为ref,表示优化器使用了user_id索引来查找与users表匹配的记录。
    6、possible_keys列:表示可能使用的索引。对users表,possible_keys为NULL,表示没有可用的索引;对于orders表,possible_keys为user_id,表示user_id是一个可能的索引。
    7、key列:表示实际使用的索引。对于users表,key为NULL,表示没有使用索引;对于orders表,key为user_id,表示使用了user_id索引。
    8、key_len列:表示索引的长度。对于orders表,key_len为5,表示user_id索引的长度为5字节(INT类型)。
    9、ref列:表示与索引比较的列或常量。对于orders表,ref为demo1.u.user_id,表示orders表中的user_id列与users表中的user_id列进行比较。
    10、rows列:表示优化器估计需要扫描的行数。对于users表,rows为 4,表示优化器估计需要扫描4行;对于orders表,rows为1,表示优化器估计每个users表的记录会匹配1行orders表的记录。
    11、filtered列:表示根据条件过滤后剩余的行数百分比。对于users表,filtered为33.33%,表示大约有三分之一的记录满足age > 30的条件;对于orders表,filtered为100.00%,表示所有匹配的记录都符合条件。
    12、Extra列:提供额外的信息。对于users表,Extra为Using where,表示使用了WHERE子句进行过滤;对于orders表,Extra为Using index,表示优化器只使用了索引中的列,而不需要访问表的数据页。

4、索引优化查询

从执行计划中可以看出,users表进行了全表扫描(ALL),这在数据量较大时会导致性能问题。为了优化查询,我们可以采取以下措施:

  • 创建索引
    为users表的age列创建索引,以加速WHERE子句中的条件过滤。
    sql示例:
CREATE INDEX idx_age ON users (age);
  • 创建覆盖索引
    为users表创建一个覆盖索引,包含user_id和name列。这样查询可以直接从索引中获取所需的数据,而不需要访问表的数据页。
    sql示例:
CREATE INDEX idx_user_name_age ON users (age, user_id, name);

运行结果:
在这里插入图片描述
优化后的执行计划解释:
1、type列:对于users表,type从ALL变为range,表示优化器现在使用了索引范围扫描,而不是全表扫描。这大大减少了需要扫描的行数。
2、key列:对于users表,key从NULL变为idx_user_name_age,表示优化器使用了新创建的覆盖索引。对于orders表,key仍然是user_id,表示继续使用user_id索引。
3、rows列:对于users表,rows从4减少到2,表示优化器估计只需要扫描2行,而不是原来的4行。这是因为age > 30的条件可以通过索引快速过滤。
4、Extra列:对于users表,Extra是Using where,Using index,表示优化器使用了索引中的列进行过滤,并且只从索引中获取数据。

5、进一步优化:使用EXISTS替代JOIN

虽然JOIN已经优化得很好,但在某些情况下,EXISTS可能比JOIN更高效,尤其是在子查询返回大量结果时。我们可以将查询改写为使用 EXISTS:
sql改写示例:

SELECT o.order_date, o.amount 
FROM orders o 
WHERE EXISTS (
    SELECT 1 
    FROM users u 
    WHERE u.user_id = o.user_id AND u.age > 30
);

运行结果:
在这里插入图片描述

通过这些优化手段,可以显著提高查询性能,减少I/O操作和CPU使用率。同时,使用EXPLAIN分析查询的执行计划,可以帮助你更好地理解优化器的行为,并找出潜在的性能瓶颈。
理解EXPLAIN输出:

  • id:查询的标识符,数值越大,优先级越高。
  • select_type:查询的类型(如简单查询、子查询、联合查询等)。
  • table:当前操作的表。
  • type:访问类型(如 ALL、index、range、ref、eq_ref、const 等)。
  • possible_keys:可能使用的索引。
  • key:实际使用的索引。
  • key_len:索引的长度。
  • ref:与索引比较的列或常量。
  • rows:估计需要扫描的行数。
  • Extra:额外的信息(如是否使用临时表、是否进行排序等)。

优化查询执行计划:

  • 避免全表扫描:尽量使用索引,减少扫描的行数。
  • 减少索引扫描范围:通过合理的索引设计,缩小查询范围。
  • 避免不必要的排序:尽量使用覆盖索引,避免回表查询。
  • 优化JOIN顺序:调整表的连接顺序,减少中间结果集的大小。

三、性能调优

MySQL的性能优化是一个多维度的过程,涉及数据库设计、查询优化、服务器配置、硬件资源等多个方面。通过合理的优化,可以显著提升MySQL数据库的响应速度、吞吐量和稳定性。

1、数据库设计优化

(1)、选择合适的数据类型
  • 使用最小的数据类型:选择能够满足需求的最小数据类型,以减少存储空间和I/O操作。例如,如果一个整数列的最大值不会超过65,535,可以使用SMALLINT而不是INT。

  • 避免使用大对象类型:尽量避免使用TEXT、BLOB等大对象类型,除非确实需要存储大量的文本或二进制数据。大对象会增加I/O开销,并且可能不适合缓存。

  • 使用枚举(ENUM)和集合(SET)类型:对于有限的选项列表,可以考虑使用ENUM或SET类型,而不是使用VARCHAR或TEXT。这些类型在存储和检索时更高效。

(2)、规范化与反规范化
  • 规范化:规范化是将数据分解为多个表,以减少冗余和提高数据一致性。虽然规范化可以提高数据的完整性和一致性,但它可能会增加连接操作的复杂性,导致查询变慢。

  • 反规范化:反规范化是通过增加冗余来减少连接操作,从而提高查询性能。例如,可以在主表中存储一些来自关联表的常用字段,以减少JOIN操作。然而,反规范化可能会导致数据冗余和维护成本增加。

建议:根据实际需求权衡规范化和反规范化的优缺点。对于频繁读取但很少更新的数据,可以适当进行反规范化;而对于频繁更新的数据,建议保持规范化。

(3)、分区表

对于非常大的表,可以考虑使用分区表(Partitioning)。分区表将数据按某种规则(如日期、范围、列表等)分散到不同的物理存储区域,从而提高查询性能和管理效率。

示例:

CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    order_date DATE,
    amount DECIMAL(10, 2)
) PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023)
);

优点:

  • 提高查询性能:分区表可以根据分区条件快速定位到所需的记录,减少全表扫描的开销。
  • 简化数据维护:分区表可以更容易地进行数据归档、清理等操作。
(4)、索引设计

索引是提升查询性能的关键。合理的索引设计可以显著加快查询速度,但过多的索引也会增加写入操作的开销。因此,索引的设计需要权衡读写性能。

  • 创建合适的索引:为查询条件列、连接条件列和排序分组的列创建索引。确保索引的选择性足够高,以减少扫描的行数。

  • 覆盖索引:覆盖索引是指索引中包含了查询所需的所有列,这样查询可以直接从索引中获取数据,而不需要访问表的数据页。覆盖索引可以显著减少I/O操作,提升查询速度。

  • 避免过度索引:虽然索引可以加速查询,但过多的索引会增加写入操作的开销。每次插入、更新或删除数据时,MySQL都需要维护索引,这会导致性能下降。因此,只创建必要的索引。

  • 使用复合索引:对于多个条件组合的查询,可以考虑创建复合索引(Composite Index)。复合索引可以同时加速多个条件的查询。
    示例:

-- 创建单列索引
CREATE INDEX idx_user_id ON users (user_id);
-- 创建复合索引
CREATE INDEX idx_user_age ON users (user_id, age);

2、查询优化

(1)、避免使用SELECT *

SELECT *会返回表中的所有列,即使某些列并不需要。这不仅增加了I/O操作和网络传输开销,还可能导致无法使用覆盖索引。因此,建议显式列出你需要的列。

示例:

-- 不推荐:返回所有列
SELECT * FROM users WHERE age > 30;

-- 推荐:只返回需要的列
SELECT user_id, name, age FROM users WHERE age > 30;
(2)、使用EXPLAIN分析查询

EXPLAIN是MySQL提供的一个工具,用于分析查询的执行计划。通过EXPLAIN,你可以了解MySQL如何执行查询,包括是否使用了索引、扫描了多少行、是否有全表扫描等。

示例:

EXPLAIN SELECT * FROM users WHERE age > 30;

EXPLAIN的输出结果包含以下重要列:

  • id:查询的标识符。
  • select_type:查询的类型。
  • table:当前操作的表。
  • type:访问类型(如 ALL、index、range、ref 等)。ALL表示全表扫描,ref表示通过索引查找。
  • possible_keys:可能使用的索引。
  • key:实际使用的索引。
  • key_len:索引的长度。
  • ref:与索引比较的列或常量。
  • rows:估计需要扫描的行数。
  • filtered:根据条件过滤后剩余的行数百分比。
  • Extra:额外的信息(如Using where、Using index、Using temporary等)。
(3)、优化JOIN查询

JOIN操作是MySQL中常见的查询方式,但也可能是性能瓶颈。为了优化JOIN查询,建议遵循以下原则:

  • 确保连接条件上有索引:为JOIN条件列创建索引,避免全表扫描。例如,在LEFT JOIN中,确保ON子句中的列上有索引。

  • 使用适当的JOIN类型:根据查询的需求选择合适的JOIN类型。例如,INNER JOIN只返回匹配的记录,而LEFT JOIN返回左表中的所有记录,即使右表中没有匹配的记录。

  • 避免嵌套子查询:嵌套子查询可能会导致性能问题,尤其是在子查询返回大量结果时。可以尝试使用JOIN替代嵌套子查询。

  • 使用EXISTS替代IN:在某些情况下,EXISTS比IN更高效,尤其是在子查询返回大量结果时。
    示例:

-- 使用 IN 子查询
SELECT * FROM orders WHERE user_id IN (SELECT user_id FROM users WHERE age > 30);
-- 使用 EXISTS 替代 IN
SELECT * FROM orders o WHERE EXISTS (SELECT 1 FROM users u WHERE u.user_id = o.user_id AND u.age > 30);
(4)、分页查询优化

分页查询通常使用LIMIT和OFFSET,但随着OFFSET的增加,查询性能会显著下降。为了避免这个问题,可以使用主键或唯一列进行分页,或者使用游标技术。

示例:

-- 使用OFFSET 进行分页(不推荐)
SELECT * FROM orders ORDER BY order_id LIMIT 10 OFFSET 9000;
-- 使用主键进行分页(推荐)
SELECT * FROM orders WHERE order_id > 9000 ORDER BY order_id LIMIT 10;
(5)、使用UNION ALL替代OR

在某些情况下,OR条件可能会导致MySQL无法使用索引,从而导致全表扫描。可以尝试使用UNION ALL替代OR,特别是在OR条件涉及不同列时。

示例:

-- 使用OR条件
SELECT * FROM users WHERE name = 'Alice' OR email = 'alice@example.com';

-- 使用UNION ALL替代OR
(SELECT * FROM users WHERE name = 'Alice')
UNION ALL
(SELECT * FROM users WHERE email = 'alice@example.com');

3、服务器配置优化

(1)、调整缓冲区大小

MySQL提供了多种缓冲区来缓存数据和索引,合理调整缓冲区大小可以显著提升性能。常用的缓冲区包括:

  • innodb_buffer_pool_size:InnoDB缓冲池的大小,用于缓存表数据和索引。建议将该参数设置为服务器内存的70%-80%,以确保足够的缓存空间。

  • query_cache_size:查询缓存的大小,用于缓存查询结果。虽然查询缓存可以加速重复查询,但在高并发场景下可能会成为性能瓶颈。建议禁用查询缓存(即:query_cache_size = 0),并使用应用层缓存(如Redis、Memcached)替代。

  • tmp_table_size和max_heap_table_size:临时表的最大大小。当查询需要创建临时表时,MySQL会优先使用内存中的临时表,但如果临时表超过这两个参数的限制,MySQL会将其转换为磁盘上的临时表,导致性能下降。建议根据实际情况调整这两个参数的大小。

(2)、启用慢查询日志

慢查询日志可以帮助你识别执行时间较长的查询,并采取相应的优化措施。

可以通过以下参数启用慢查询日志:

  • slow_query_log:启用或禁用慢查询日志。
  • long_query_time:设置慢查询的时间阈值(单位为秒)。超过这个时间的查询会被记录到慢查询日志中。
  • log_queries_not_using_indexes:是否记录不使用索引的查询。

配置示例:

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 2
log_queries_not_using_indexes = 1
(3)、调整InnoDB配置

InnoDB是MySQL的默认存储引擎,合理的InnoDB配置可以显著提升性能。

常用的InnoDB参数包括:

  • innodb_buffer_pool_size:如前所述,建议将该参数设置为服务器内存的70%-80%。
  • innodb_flush_method:设置InnoDB的刷新方法。O_DIRECT可以避免双倍缓冲(即操作系统缓存和InnoDB缓存同时存在),减少I/O开销。
  • innodb_flush_log_at_trx_commit:控制事务提交时的日志刷新行为。1表示每次提交时都刷新日志,保证数据的安全性;2表示每秒刷新一次日志,适合对性能要求较高的场景。
  • innodb_io_capacity:设置磁盘I/O的最大容量。根据你的磁盘性能调整该参数,以充分利用磁盘带宽。

4、硬件资源优化

(1)、选择合适的硬件
  • CPU:选择多核CPU,以支持多线程并发处理。MySQL是多线程应用程序,能够充分利用多核CPU的优势。
  • 内存:增加内存可以显著提升MySQL的性能,特别是对于InnoDB缓冲池和其他缓冲区。建议将内存的70%-80%用于InnoDB缓冲池。
  • 磁盘:使用SSD(固态硬盘)代替传统HDD(机械硬盘),以提高I/O性能。SSD的随机读写速度远高于HDD,特别适合InnoDB的小块I/O操作。
  • 网络:确保数据库服务器和应用服务器之间的网络带宽充足,避免网络延迟影响性能。
(2)、使用RAID

RAID(独立磁盘冗余阵列)可以提高磁盘的读写性能和数据安全性。

常用的RAID级别包括:

  • RAID 0:条带化,提供最高的读写性能,但没有冗余,任何一块磁盘故障都会导致数据丢失。
  • RAID 1:镜像,提供数据冗余,但读写性能较低。
  • RAID 10:结合了RAID 0和RAID 1的优点,既有条带化的高性能,又有镜像的冗余性,适合MySQL数据库。
(3)、使用分布式数据库

对于非常大的数据集或高并发场景,可以考虑使用分布式数据库(如MySQL Cluster、Galera Cluster、TiDB等)。分布式数据库可以将数据分布到多个节点上,提升系统的扩展性和容错能力。

5、监控与调优

(1)、使用性能监控工具

定期监控MySQL的性能指标,及时发现潜在的问题。

常用的性能监控工具包括:

  • SHOW STATUS和SHOW VARIABLES:查看MySQL的运行状态和配置参数。
  • SHOW PROCESSLIST:查看当前正在执行的查询,帮助你发现长时间运行的查询。
  • Performance Schema:MySQL内置的性能监控工具,提供了详细的性能统计信息。
  • Percona Monitoring and Management (PMM):Percona提供的开源监控工具,支持MySQL、MongoDB等数据库的性能监控。
  • Prometheus + Grafana:开源的监控和可视化工具,可以与MySQL结合使用,提供实时的性能监控和报警功能。
(2)、定期分析慢查询日志

慢查询日志是发现性能瓶颈的重要工具。可以使用mysqldumpslow或pt-query-digest等工具解析慢查询日志,找出最耗时的查询,并采取相应的优化措施。

(3)、使用EXPLAIN ANALYZE

MySQL 8.0引入了EXPLAIN ANALYZE命令,它不仅可以显示查询的执行计划,还可以实际执行查询并返回详细的性能统计信息。这对于分析复杂的查询非常有用。

示例:

EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;

6、Mysql性能优化总结

MySQL性能优化是一个持续的过程,涉及多个方面的技术和策略。通过合理的数据库设计、查询优化、服务器配置和硬件资源优化,可以显著提升MySQL的性能和稳定性。

以下是关键的优化建议:
(1)、数据库设计:选择合适的数据类型,规范化与反规范化相结合,使用分区表和索引设计。
(2)、查询优化:避免使用SELECT *,使用EXPLAIN分析查询,优化JOIN和分页查询。
(3)、服务器配置:调整缓冲区大小,启用慢查询日志,优化InnoDB配置。
(4)、硬件资源:选择合适的硬件,使用SSD和RAID,考虑分布式数据库。
(5)、监控与调优:使用性能监控工具,定期分析慢查询日志,使用EXPLAIN ANALYZE深入分析查询性能。

四、慢日志分析

MySQL的慢查询日志(Slow Query Log)是用于记录执行时间超过指定阈值的SQL查询的日志文件。通过分析慢查询日志,可以发现性能瓶颈并优化查询。

1、启用慢查询日志

(1)、全局配置文件

全局配置文件中启用:
要永久启用慢查询日志,可以在MySQL的全局配置文件my.cnf或my.ini中进行设置。

配置示例:

[mysqld]
# 启用慢查询日志
slow_query_log = 1

# 指定慢查询日志文件路径(可选)
slow_query_log_file = /var/log/mysql/slow-query.log

# 设置慢查询的时间阈值(单位:秒,默认为10秒)
long_query_time = 2

# 是否记录不使用索引的查询(可选)
log_queries_not_using_indexes = 1

# 是否记录管理员命令(如ALTER TABLECREATE INDEX等,可选)
log_slow_admin_statements = 1

# 是否记录所有查询(包括快速查询,可选)
log_slow_slave_statements = 1

解释:

  • slow_query_log:启用或禁用慢查询日志。1表示启用,0表示禁用。
  • slow_query_log_file:指定慢查询日志文件的路径。如果不指定,默认会存储在数据目录下,文件名为hostname-slow.log。
  • long_query_time:设置查询执行时间的阈值(单位为秒)。超过这个时间的查询会被记录到慢查询日志中。默认值为10秒,建议根据实际情况调整。
  • log_queries_not_using_indexes:是否记录不使用索引的查询。启用后,即使查询执行时间很短,但如果没有使用索引的查询也会被记录。
  • log_slow_admin_statements:是否记录管理员命令(如ALTER TABLE、CREATE INDEX等)。这些命令通常是耗时操作,记录它们有助于分析数据库的整体性能。
  • log_slow_slave_statements:是否记录从库上的慢查询。这对于主从复制环境中的性能分析非常有用。
(2)、动态启用慢查询日志

如果你不想修改配置文件,可以通过动态设置系统变量来临时启用慢查询日志。这样可以在不重启MySQL服务的情况下启用或禁用慢查询日志。

sql示例:

-- 启用慢查询日志
SET GLOBAL slow_query_log = 1;

-- 设置慢查询日志文件路径
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log';

-- 设置慢查询的时间阈值(单位:秒)
SET GLOBAL long_query_time = 2;

-- 是否记录不使用索引的查询
SET GLOBAL log_queries_not_using_indexes = 1;

注意:
动态设置的参数只在当前会话或服务器运行期间有效,重启MySQL服务后会恢复为默认值。因此,如果需要永久生效,建议修改配置文件。

2、查看慢查询日志

(1)、直接查看日志文件

慢查询日志文件通常是一个文本文件,可以直接使用文本编辑器(如vi、nano)或命令行工具(如cat、less)查看。

例如:
使用 less 查看慢查询日志
命令示例:

less /var/log/mysql/slow-query.log

使用 tail 查看最新的慢查询
命令示例:

tail -f /var/log/mysql/slow-query.log
(2)、使用mysqldumpslow工具

MySQL提供了一个内置工具mysqldumpslow,用于解析和汇总慢查询日志。它可以帮助你快速找到最耗时的查询,并统计每个查询的出现次数和平均执行时间。

常用命令示例:
显示慢日志slow-query.log中前 10 条最耗时的查询

mysqldumpslow -s t -n 10 /var/log/mysql/slow-query.log

显示出现次数最多的 10 条查询

mysqldumpslow -s c -n 10 /var/log/mysql/slow-query.log

显示按平均时间排序的 10 条查询(对相同查询sql,可能第1次10秒,第2次2秒,这中场景下,取平均时间更可靠一点)

mysqldumpslow -s at -n 10 /var/log/mysql/slow-query.log

显示包含特定关键词的查询(例如 ‘users’ 表)

mysqldumpslow -g 'users' /var/log/mysql/slow-query.log

解释:

  • -s:指定排序方式。常见的选项有:
    • t:按总时间排序。
    • c:按查询次数排序。
    • at:按平均时间排序。
    • l:按锁定时间排序。
    • r:按返回的行数排序。
  • -n:限制输出的查询数量。
  • -g:使用正则表达式过滤特定的查询。
(3)、使用pt-query-digest工具

pt-query-digest是Percona Toolkit中的一个强大工具,用于分析慢查询日志。相比于mysqldumpslow,pt-query-digest提供了更详细的统计信息和更好的可视化效果。它可以解析MySQL的慢查询日志、通用查询日志(General Query Log)以及二进制日志(Binary Log)。

安装Percona Toolkit示例:
Ubuntu/Debian环境:

sudo apt-get install percona-toolkit

CentOS/RHEL环境:

sudo yum install percona-toolkit

常用命令:

 分析慢查询日志
pt-query-digest /var/log/mysql/slow-query.log

 分析二进制日志
pt-query-digest --type binlog /path/to/binlog.000001

 分析通用查询日志
pt-query-digest --type genlog /path/to/general-query.log

解释:
pt-query-digest会生成详细的报告,包括:

  • 查询的执行频率。
  • 查询的平均、最大和最小执行时间。
  • 查询的锁定时间。
  • 查询返回的行数。
  • 查询的I/O和CPU使用情况。
  • 查询的执行计划(如果有)。

3、分析慢查询日志

(1)、识别问题查询

通过查看慢查询日志,你可以识别出哪些查询执行时间过长,或者哪些查询没有使用索引。

以下是常见的问题查询类型:

  • 全表扫描(Table Scan):查询没有使用索引,导致MySQL需要扫描整个表。这种查询通常会导致I/O操作增加,尤其是在大表上。
    解决方法:为查询条件列创建合适的索引,避免全表扫描。

  • 未使用索引的查询:即使表上有索引,某些查询可能仍然没有使用索引。这可能是由于查询条件不符合索引的设计,或者查询涉及多个表的连接操作。
    解决方法:检查查询的EXPLAIN执行计划,确保查询能够正确使用索引。如果无法使用现有索引,考虑创建新的索引或调整查询逻辑。

  • 复杂的子查询或连接操作:涉及多个表的连接操作或嵌套子查询可能会导致查询性能下降,尤其是在没有适当索引的情况下。
    解决方法:优化查询结构,尽量使用JOIN替代嵌套子查询,并确保连接条件上有适当的索引。

  • 大量返回行数的查询:某些查询可能返回大量的行,导致网络传输和内存占用增加。
    解决方法:限制返回的行数,使用分页查询(如LIMIT和OFFSET),或者只选择需要的列,避免不必要的数据传输。

(2)、使用EXPLAIN分析查询

对于每个慢查询,建议使用EXPLAIN来分析其执行计划。EXPLAIN可以帮助你了解MySQL如何执行查询,包括是否使用了索引、扫描了多少行、是否有全表扫描等。

示例:

EXPLAIN SELECT * FROM users WHERE age > 30;

** EXPLAIN的输出结果包含以下重要列:**

  • id:查询的标识符。相同的id表示查询属于同一个查询块。
  • select_type:查询的类型(如SIMPLE、PRIMARY、SUBQUERY等)。
  • table:当前操作的表。
  • partitions:涉及的分区(如果有分区表)。
  • type:访问类型(如ALL、index、range、ref等)。ALL 表示全表扫描,ref表示通过索引查找。
  • possible_keys:可能使用的索引。
  • key:实际使用的索引。
  • key_len:索引的长度。
  • ref:与索引比较的列或常量。
  • rows:估计需要扫描的行数。
  • filtered:根据条件过滤后剩余的行数百分比。
  • Extra:额外的信息(如Using where、Using index、Using temporary等)。
    通过EXPLAIN,你可以发现查询是否存在性能问题,并采取相应的优化措施。
(3)、使用SHOW PROFILES和SHOW PROFILE

MySQL还提供了SHOW PROFILES和SHOW PROFILE命令,用于查看单个查询的详细性能信息。SHOW PROFILES可以列出最近执行的所有查询及其执行时间,而SHOW PROFILE可以显示某个查询的具体性能指标。

查看当前MySQL是否支持profile操作:

SELECT @@have_profiling ;

运行结果:
在这里插入图片描述
YES标识数据库支持profile操作。

查看mysql是否开启profile:

SELECT @@profiling ;

运行结果:
在这里插入图片描述
1标识开启,0为未开启。

开启或关闭profile:
开启profile

SET profiling = 1;

在这里插入图片描述

profiles查看最近执行的查询及其执行时间:
可以查看sql的queryId和时间等信息。
示例:

select * from sys_user where id = '2a01983a00d6533524f84bffcf07fa58';
select * from sys_user where name = '李四';
select id,name,GENDER from sys_user where name = '李四';
show profiles;      // 查看profile的queryId等

运行结果:
在这里插入图片描述
解释:
profiles可以帮我们看到sql以及queryId和耗时等信息,可以使用profile语句,对queryId的查询进一步分析。

profile查看某个查询的详细性能信息:
通过上诉我们可以查询到sql的queryId,之后可以进一步分析消耗。

show profile for query 6;
show profile cpu for query 6;

运行结果:
在这里插入图片描述
解释:
SHOW PROFILE 的输出结果包含以下性能指标:(Duration为某项指标总耗时,后面两个为user耗时和system耗时)

  • query end:查询结束时间。
  • sending data:发送数据的时间。
  • sorting result:排序结果的时间。
  • executing:执行查询的时间。
  • statistics:获取统计信息的时间。
  • parsing:解析查询的时间。
  • opening tables:打开表的时间。
  • locking tables:锁定表的时间。

4、优化慢查询

一旦识别出慢查询,接下来就是优化它们。
常见的优化手段包括:
1、创建合适的索引:为查询条件列创建索引,避免全表扫描。确保索引的选择性足够高,以减少扫描的行数。
2、优化查询语句:避免使用SELECT *,只选择需要的列。使用JOIN替代嵌套子查询,简化查询结构。
3、使用覆盖索引:确保查询所需的所有列都在索引中,避免回表操作。
4、优化表结构:选择合适的数据类型,避免使用过大的列(如TEXT、BLOB)。对于大表,考虑使用分区表或水平拆分表。
5、使用缓存:对于不经常变化的数据,可以使用Redis、Memcached等缓存系统来减少对数据库的频繁查询。
6、调整数据库配置:优化MySQL的缓冲区大小、查询缓存、并行查询等配置参数,提升整体性能。

5、慢日志总结

MySQL的慢查询日志是分析和优化查询性能的重要工具。通过启用慢查询日志,你可以记录执行时间较长的查询,并使用mysqldumpslow或pt-query-digest等工具进行分析。结合 EXPLAIN和SHOW PROFILES,你可以深入了解查询的执行计划和性能瓶颈,从而采取相应的优化措施。
常见的优化手段包括创建合适的索引、优化查询语句、使用覆盖索引、优化表结构等。通过这些方法,可以显著提高查询性能,减少资源消耗,并提升系统的响应速度。
如果你发现某些查询频繁出现在慢查询日志中,建议定期对其进行优化,并监控其性能变化。此外,定期清理不再需要的慢查询日志文件,以避免日志文件过大影响系统性能。

乘风破浪会有时,直挂云帆济沧海!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CV项目详解:基于yolo8的车辆识别系统(含源码和具体教程)

使用YOLOv8(You Only Look Once)和OpenCV实现车道线和车辆检测,目标是创建一个可以检测道路上的车道并识别车辆的系统,并估计它们与摄像头的距离。该项目结合了计算机视觉技术和深度学习物体检测。 使用YOLOv8和OpenCV实现车道线…

osg中实现模型的大小、颜色、透明度的动态变化

以博饼状模型为对象,实现了模型大小、颜色、透明度的动态变化。 需要注意的是一点: // 创建材质对象osg::ref_ptr<osg::Material> material = new osg::Material;material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0, 1.0, 0.0, 0.5));// 获取模型的…

小米vela系统(基于开源nuttx内核)——openvela开源项目

前言 在 2024 年 12 月 27 日的小米「人车家全生态」合作伙伴大会上&#xff0c;小米宣布全面开源 Vela 操作系统。同时&#xff0c;OpenVela 项目正式上线 GitHub 和 Gitee&#xff0c;采用的是比较宽松的 Apache 2.0 协议&#xff0c;这意味着全球的开发者都可以参与到 Vela…

《数据思维》之数据可视化_读书笔记

文章目录 系列文章目录前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 数据之道&#xff0c;路漫漫其修远兮&#xff0c;吾将上下而求索。 一、数据可视化 最基础的数据可视化方法就是统计图。一个好的统计图应该满足四个标准&#xff1a;准确、有…

AI刷题-最大矩形面积问题、小M的数组变换

目录 一、最大矩形面积问题 问题描述 输入格式 输出格式 输入样例 输出样例 数据范围 解题思路&#xff1a; 问题理解 数据结构选择 算法步骤 最终代码&#xff1a; 运行结果&#xff1a; 二、小M的数组变换 问题描述 测试样例 解题思路&#xff1a; 问题…

数据库(MySQL)练习

数据库&#xff08;MySQL&#xff09;练习 一、练习1.15练习练习 二、注意事项2.1 第四天 一、练习 1.15练习 win11安装配置MySQL超详细教程: https://baijiahao.baidu.com/s?id1786910666566008458&wfrspider&forpc 准备工作&#xff1a; mysql -uroot -p #以管理…

C语言:-三子棋游戏代码:分支-循环-数组-函数集合

思路分析&#xff1a; 1、写菜单 2、菜单之后进入游戏的操作 3、写函数 实现游戏 3.1、初始化棋盘函数&#xff0c;使数组元素都为空格 3.2、打印棋盘 棋盘的大概样子 3.3、玩家出棋 3.3.1、限制玩家要下的坐标位置 3.3.2、判断玩家要下的位置是否由棋子 3.4、电脑出棋 3.4.1、…

知识图谱常见的主流图数据库

在知识图谱中&#xff0c;主流使用的图数据库包括以下几种&#xff1a; Neo4j&#xff1a;这是目前全球部署最广泛的图数据库之一&#xff0c;具有强大的查询性能和灵活的数据模型&#xff0c;适用于复杂关系数据的存储和查询。 JanusGraph&#xff1a;JanusGraph是一个开源的…

Nginx三种不同类型的虚拟主机(基于域名、IP 和端口)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; Nginx-从零开始的服务器之旅专栏&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年1月15日13点14分 目录 1. 基于域名的虚拟主机 …

RabbitMQ(四)

SpringBoot整合RabbitMQ SpringBoot整合1、生产者工程①创建module②配置POM③YAML④主启动类⑤测试程序 2、消费者工程①创建module②配置POM③YAML文件内配置&#xff1a; ④主启动类⑤监听器 3、RabbitListener注解属性对比①bindings属性②queues属性 SpringBoot整合 1、生…

java_将数据存入elasticsearch进行高效搜索

使用技术简介&#xff1a; (1) 使用Nginx实现反向代理&#xff0c;使前端可以调用多个微服务 (2) 使用nacos将多个服务管理关联起来 (3) 将数据存入elasticsearch进行高效搜索 (4) 使用消息队列rabbitmq进行消息的传递 (5) 使用 openfeign 进行多个服务之间的api调用 参…

win32汇编环境,对话框程序中组合框的应用举例

;运行效果 ;win32汇编环境,对话框程序中组合框的应用举例 ;比如在对话框中生成组合框&#xff0c;增加子项&#xff0c;删除某项&#xff0c;取得指定项内容等 ;直接抄进RadAsm可编译运行。重点部分加备注。 ;以下是ASM文件 ;>>>>>>>>>>>>…

occ的开发框架

occ的开发框架 1.Introduction This manual explains how to use the Open CASCADE Application Framework (OCAF). It provides basic documentation on using OCAF. 2.Purpose of OCAF OCAF (the Open CASCADE Application Framework) is an easy-to-use platform for ra…

Linux检查磁盘占用情况

1.检查使用情况 df -h发现是/dev/vda1占用很高 2.查看/dev/vda1文件夹 cd /dev/vda1发现不是文件夹 3.继续查看使用情况 df -h *4.原因可能是文件已经删除但是进程还在&#xff0c;没有释放空间 5.查看删除操作的进程 lsof -n | grep deleted6.杀死进程 kill -9 PID

C# (图文教学)在C#的编译工具Visual Studio中使用SQLServer并对数据库中的表进行简单的增删改查--14

目录 一.安装SQLServer 二.在SQLServer中创建一个数据库 1.打开SQL Server Manager Studio(SSMS)连接服务器 2.创建新的数据库 3.创建表 三.Visual Studio 配置 1.创建一个简单的VS项目(本文创建为一个简单的控制台项目) 2.添加数据库连接 四.简单连通代码示例 简单连…

Flutter插件制作、本地/远程依赖及缓存机制深入剖析(原创-附源码)

Flutter插件在开发Flutter项目的过程中扮演着重要的角色&#xff0c;我们从 ​​​​​​https://pub.dev 上下载添加到项目中的第三方库都是以包或者插件的形式引入到代码中的&#xff0c;这些第三方工具极大的提高了开发效率。 深入的了解插件的制作、发布、工作原理和缓存机…

自动化办公|xlwings简介

xlwings 是一个开源的 Python 库&#xff0c;旨在实现 Python 与 Microsoft Excel 的无缝集成。它允许用户使用 Python 脚本自动化 Excel 操作&#xff0c;读取和写入数据&#xff0c;执行宏&#xff0c;甚至调用 VBA 脚本。这使得数据分析、报告生成和其他与 Excel 相关的任务…

Dify应用-工作流

目录 DIFY 工作流参考 DIFY 工作流 2025-1-15 老规矩感谢参考文章的作者,避免走弯路。 2025-1-15 方便容易上手 在dify的一个桌面上,添加多个节点来完成一个任务。 每个工作流必须有一个开始和结束节点。 节点之间用线连接即可。 每个节点可以有输入和输出 输出类型有,字符串,…

《C++11》并发库:简介与应用

在C11之前&#xff0c;C并没有提供原生的并发支持。开发者通常需要依赖于操作系统的API&#xff08;如Windows的CreateThread或POSIX的pthread_create&#xff09;或者第三方库&#xff08;如Boost.Thread&#xff09;来创建和管理线程。这些方式存在以下几个问题&#xff1a; …

建筑综合布线可视化管理

随着数字化转型的加速&#xff0c;越来越多的业务应用依赖网络来实现&#xff0c;综合布线系统作为网络基础设施&#xff0c;加强对综合布线系统的管理维护是业务安全稳定运行的重要保障。传统的表格CAD图纸的综合布线管理模式&#xff0c;易造成综合布线系统线缆混乱、随意变更…