一文道尽数据库底层原理,探讨Mysql调优之道

Posted 小飞龙编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文道尽数据库底层原理,探讨Mysql调优之道相关的知识,希望对你有一定的参考价值。

前段时间看过一部电影,叫做《英雄时代》,里面有句话是这样说的:“生活这条狗啊,追的我连从容撒泡尿的时间都没有。”

在这个聪明人满街乱窜的年代,稀缺的恰恰不是聪明,而是一心一意,孤注一掷,一条心,一根筋。

人生最可怕的是,一生碌碌无为,还安慰自己平凡可贵。

数据库调优

慢查询日志

慢查询日志是mysql内置的一项功能,可以记录执行超过指定时间的Sql语句

考虑到慢查询日志细节比较多,在这里我专门记录了一部分手记,一起来看一下:

相关参数与默认值

参数作用默认值
log_output日志输出到哪,默认FILE,表示文件;设置成TABLE,则将日志记录到mysql.slow_log中。也可能设置多种格式,比如:FILE,TABLEFILE
long_query_time执行时间超过这么久才记录到慢查询日志,单位秒,可使用小数表示小于秒的时间10
log_queries_not_using_indexes是否要将未使用索引的SQL记录到慢查询日志中,此配置会无视log_query_time的配置。生产环境建议关闭;开发环境建议开启。OFF
log_throttle_queries_not_using_indexes和log_queries_not_using_indexes配合使用,如果log_queries_not_using_indexes打开,则该参数将限制每分钟写入的、未使用索引的SQL数量。0
min_examined_row_limit扫描行数至少达到这么多才记录的慢查询日志0
log_slow_admin_statements是否要记录管理语句,默认关闭。管理语句包括ALERT TABLE,ANALYZE TABLE,CHECK TABLE,CREATE INDEX,DROP INDEX,OPTIMIZE TABLE,and REPAIR TABLEOFF
slow_query_log_file指定慢查询日志文件路径/var路径
log_slow_slave_statements该参数在从库上设置,决定是否记录在复制过程中超过long_query_time的SQL。如果binlog格式是row,则该参数无效OFF
log_slow_extra当log_output=FILE时,是否要记录额外信息(MySql 8.0.14开始提供),对log_output=TABLE的结果无影响。OFF

使用方式

方式一、修改配置文件my.cnf,在[mysqld]段落中加上如下参数即可
例如:

[mysqld]
#...
log_output = 'FILE,TABLE'
slow_query_log = ON
long_query_time = 0.001

然后重启mysql

service mysqld restart

方式二、通过全局变量设置

这种方式无需重启即可生效,但一旦重启,配置又会失效。

例如:

set global log_output = 'FILE,TABLE';
set global slow_query_log = 'NO';
set global long_query_time = 0.001;

这样设置之后,就会将慢查询日志同时记录到文件以及mysql.slow_log表中。

分析慢查询日志

分析慢查询日志表

当log_output = TABLE时,可直接用如下语句分析:

select * from `mysql`.slow_log

然后按照条件做各种查询、统计、分析。

分析慢查询日志文件

mysqldumpslow
当log_output = FILE时,可使用mysqldumpslow分析

[server@server-test ~]$ mysqldumpslow --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]

Parse and summarize the MySQL slow query log. Options are

  --verbose    verbose
  --debug      debug
  --help       write this text to standard output

  -v           展示更详细的信息
  -d           debug
  -s ORDER     以哪种方式排序 (al, at, ar, c, l, r, t), 默认 'at' 
                al: 平均锁定时间
                ar: 平均返回记录数
                at: 平均查询时间
                 c: 访问计数
                 l: 锁定时间
                 r: 返回记录
                 t: 查询时间
  -r           将-s的排序倒序
  -t NUM       top n的意思,展示最前面的几条
  -a           不去将数字展示成N,将字符串展示成'S'
  -n NUM       abstract numbers with at least n digits within names
  -g PATTERN   后边可以写一个正则,只有符合正则的行会展示
  -h HOSTNAME  慢查询日志以 主机名 =slow.log的格式命名,-h可指定读取指定主机名的慢查询日志,默认情况下是*,读取所有的慢查询日志
  -i NAME      Mysql Server的实例名称(如果使用了mysql.server startup脚本的话)
  -l           不将锁定时间从总时间减去

pt-query-digest
我们也可以用pt-query-digest分析慢查询日志文件。pt-query-digest是Percona公司开发的工具,是Percona Toolkit工具套件的使用工具之一。这里就不详细探究了,感兴趣的同学自行研究吧。

EXPLAIN详解

explain可以帮助我们分析mysql的执行计划,

EXPLAIN使用

explain可用来分析SQL的执行计划。

我们来演示一下:

这样我们就可以知道

SELECT * from user_info where nickname = 'Ant'

这条Sql语句是怎样执行的了。

结果输出展示:

字段format=json时的名称含义
idselect_id该语句的唯一标识
select_type查询类型
tabletable_name表名
partitionspartitions匹配的分区
typeaccess_type连接类型
possible_keyspossible_keys可能的索引选择
keykey实际选择的索引
key_lenkey_length索引的长度
refref索引的哪一列被引用了
rowsrows估计要扫描的行
filteredfiltered表示符合查询条件的数据百分比
Extra没有附加信息

接下来我们分析一下执行的结果:

首先,这里的select_type是SIMPLE 表示这是一个简单查询,table表示查询的表是user_info ,type是ALL表示发生了全表扫描,possible_keys、key、key_len都是空,表示没有使用任何索引,rows表示执行这个sql需要扫描25万多数据才能返回,filtered是10%,最后Extra是Using where表示使用了where条件。

根据这个分析来看,这条sql的性能是比较差的。
我们执行一下看看:

看到花费了800多毫秒,性能果然不太OK。

我们再来看下面一段演示:


从这里我们可以发现,explain执行后展示了两行结果,当有多条结果的时候这个id字段是有用的,它可以描述sql的执行过程。如果一个explain的执行结果包含多个id值,比如id=1以及id=2那么数字越大越先执行;而对于相同id的行,比如上图中id都是1,那么会从上到下依次执行。

SQL性能分析

一般来说,使用Explain已经满足大多数场景下分析SQL的需求,但是如果想更加细致的分析SQL的话,Explain可能还是不够的,那我们就来探讨一下,如何深入到Sql内部,去了解一条Sql到底执行了哪些步骤,每个步骤花费了多久,性能瓶颈出现在了哪个步骤。

如何深入SQL内部,去分析其性能,包括了三种方式:

  • SHOW PROFILE
  • INFORMATION_SCHEMA.PROFILING
  • PERFORMANCE_SCHEMA

SHOW PROFILE

SHOW PROFILE是MySQL的一个性能分析指令,可以跟踪SQL各种资源消耗。使用格式如下:

SHOW PROFILE [type [, type] ... ]
    [FOR QUERY n]
    [LIMIT row_count [OFFSET offset]]

type: {
    ALL                     显示所有信息
  | BLOCK IO                显示阻塞的输入输出次数
  | CONTEXT SWITCHES				显示自愿及非自愿的上下文切换次数
  | CPU											显示用户与系统CPU使用时间
  | IPC											显示消息发送与接收的次数
  | MEMORY									显示内存相关的开销,目前未实现此功能
  | PAGE FAULTS							显示页错误相关开销信息
  | SOURCE									列出相应操作对应的函数名及其在源码中的位置()
  | SWAPS										显示swap交换次数
}

默认情况下,SHOW PROFILE只展示Status和Duration两列,如果想展示更多信息,可指定type。

  • 使用如下命令,查看是否支持SHOW PROFILE功能,yes标志支持。从MySQL 5.0.37开始,MySQL支持SHOW PROFILE

    select @@have_profiling;
    
  • 查看当前是否启用了SHOW PROFILE,0表示未启用,1表示已启用

    select @@profiling;
    
  • 使用如下命令为当前会话开启或关闭性能分析,设成1表示开启,0表示关闭

    set profiling = 1;
    
  • 使用SHOW PROFILES命令,可为最近发送的SQL语句做一个概要的性能分析。展示的条目数目由profiling_history_size会话变量控制,该变量的默认值为15。最大值为100。将值设置为0具有禁用分析的实际效果。

  • – 默认展示15条

    show profiles
    
    -- 使用profiling_history_size调整展示的条目数
    set profiling_history_size = 100;
    
  • 使用show profile分析指定查询:

    mysql> SHOW PROFILES;
    +----------+----------+--------------------------+
    | Query_ID | Duration | Query                    |
    +----------+----------+--------------------------+
    |        0 | 0.000088 | SET PROFILING = 1        |
    |        1 | 0.000136 | DROP TABLE IF EXISTS t1  |
    |        2 | 0.011947 | CREATE TABLE t1 (id INT) |
    +----------+----------+--------------------------+
    3 rows in set (0.00 sec)
    
    mysql> SHOW PROFILE;
    +----------------------+----------+
    | Status               | Duration |
    +----------------------+----------+
    | checking permissions | 0.000040 |
    | creating table       | 0.000056 |
    | After create         | 0.011363 |
    | query end            | 0.000375 |
    | freeing items        | 0.000089 |
    | logging slow query   | 0.000019 |
    | cleaning up          | 0.000005 |
    +----------------------+----------+
    7 rows in set (0.00 sec)
    
    -- 默认情况下,只展示Status和Duration两列,如果想展示更多信息,可指定type。
    mysql> SHOW PROFILE FOR QUERY 1;
    +--------------------+----------+
    | Status             | Duration |
    +--------------------+----------+
    | query end          | 0.000107 |
    | freeing items      | 0.000008 |
    | logging slow query | 0.000015 |
    | cleaning up        | 0.000006 |
    +--------------------+----------+
    4 rows in set (0.00 sec)
    
    -- 展示CPU相关的开销
    mysql> SHOW PROFILE CPU FOR QUERY 2;
    +----------------------+----------+----------+------------+
    | Status               | Duration | CPU_user | CPU_system |
    +----------------------+----------+----------+------------+
    | checking permissions | 0.000040 | 0.000038 |   0.000002 |
    | creating table       | 0.000056 | 0.000028 |   0.000028 |
    | After create         | 0.011363 | 0.000217 |   0.001571 |
    | query end            | 0.000375 | 0.000013 |   0.000028 |
    | freeing items        | 0.000089 | 0.000010 |   0.000014 |
    | logging slow query   | 0.000019 | 0.000009 |   0.000010 |
    | cleaning up          | 0.000005 | 0.000003 |   0.000002 |
    +----------------------+----------+----------+------------+
    7 rows in set (0.00 sec) ```
    
    
  • 分析完成后,记得关闭掉SHOW PROFILE功能:

    set profiling = 0;
    

TIPS

  • MySQL官方文档声明SHOW PROFILE已被废弃,并建议使用Performance Schema作为替代品。
  • 在某些系统上,性能分析只有部分功能可用。比如,部分功能在Windows系统下无效(show profile使用了getrusage()这个API,而在Windows上将会返回false,因为Windows不支持这个API);此外,性能分析是进程级的,而不是线程级的,这意味着其他线程的活动可能会影响到你看到的计时信息。

INFORMATION_SCHEMA.PROFILING

INFORMATION_SCHEMA.PROFILING用来做性能分析。它的内容对应SHOW PROFILE和SHOW PROFILES 语句产生的信息。除非设置了 set profiling = 1; ,否则该表不会有任何数据。该表包括以下字段:

  • QUERY_ID:语句的唯一标识
  • SEQ:一个序号,展示具有相同QUERY_ID值的行的显示顺序
  • STATE:分析状态
  • DURATION:在这个状态下持续了多久(秒)
  • CPU_USER,CPU_SYSTEM:用户和系统CPU使用情况(秒)
  • CONTEXT_VOLUNTARY,CONTEXT_INVOLUNTARY:发生了多少自愿和非自愿的上下文转换
  • BLOCK_OPS_IN,BLOCK_OPS_OUT:块输入和输出操作的数量
  • MESSAGES_SENT,MESSAGES_RECEIVED:发送和接收的消息数
  • PAGE_FAULTS_MAJOR,PAGE_FAULTS_MINOR:主要和次要的页错误信息
  • SWAPS:发生了多少SWAP
  • SOURCE_FUNCTION,SOURCE_FILE,SOURCE_LINE:当前状态是在源码的哪里执行的

TIPS

  • SHOW PROFILE本质上使用的也是INFORMATION_SCHEMA.PROFILING
  • INFORMATION_SCHEMA.PROFILING表已被废弃,在未来可能会被删除。未来将可使用Performance Schema替代,详见 “Query Profiling Using Performance Schema”
  • 下面两个SQL是等价的:
    SHOW PROFILE FOR QUERY 2;
    
    SELECT STATE, FORMAT(DURATION, 6) AS DURATION
    FROM INFORMATION_SCHEMA.PROFILING
    WHERE QUERY_ID = 2 ORDER BY SEQ;
    

PERFORMANCE_SCHEMA

PERFORMANCE_SCHEMA是MySQL建议的性能分析方式,未来SHOW PROFILE、INFORMATION_SCHEMA.PROFILING都会废弃。据笔者研究,PERFORMANCE_SCHEMA在MySQL 5.6引入,因此,在MySQL 5.6及更高版本才能使用。可使用SHOW VARIABLES LIKE 'performance_schema';查看启用情况,MySQL 5.7开始默认启用。

下面来用PERFORMANCE_SCHEMA去实现SHOW PROFILE类似的效果:

  • 查看是否开启性能监控

    mysql> SELECT * FROM performance_schema.setup_actors;
    +------+------+------+---------+---------+
    | HOST | USER | ROLE | ENABLED | HISTORY |
    +------+------+------+---------+---------+
    | %    | %    | %    | YES     | YES     |
    +------+------+------+---------+---------+
    

    默认是开启的。

  • 你也可以执行类似如下的SQL语句,只监控指定用户执行的SQL:

    mysql> UPDATE performance_schema.setup_actors
      	 SET ENABLED = 'NO', HISTORY = 'NO'
       	WHERE HOST = '%' AND USER = '%';
    
    mysql> INSERT INTO performance_schema.setup_actors
           (HOST,USER,ROLE,ENABLED,HISTORY)
           VALUES('localhost','test_user','%','YES','YES');
    

    这样,就只会监控localhost机器上test_user用户发送过来的SQL。其他主机、其他用户发过来的SQL统统不监控。

  • 执行如下SQL语句,开启相关监控项:

    mysql> UPDATE performance_schema.setup_instruments
           SET ENABLED = 'YES', TIMED = 'YES'
           WHERE NAME LIKE '%statement/%';
           
    mysql> UPDATE performance_schema.setup_instruments
           SET ENABLED = 'YES', TIMED = 'YES'
           WHERE NAME LIKE '%stage/%';
           	       
    mysql> UPDATE performance_schema.setup_consumers
           SET ENABLED = 'YES'
           WHERE NAME LIKE '%events_statements_%';
           	
    mysql> UPDATE performance_schema.setup_consumers
           SET ENABLED = 'YES'
           WHERE NAME LIKE '%events_stages_%';  
           
    
  • 使用开启监控的用户,执行SQL语句,比如:

    mysql> SELECT * FROM employees.employees WHERE emp_no = 10001;
    +--------+------------+------------+-----------+--------+------------+
    | emp_no | birth_date | first_name | last_name | gender | hire_date |
    +--------+------------+------------+-----------+--------+------------+
    |  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
    +--------+------------+------------+-----------+--------+------------+
    
  • 执行如下SQL,获得语句的EVENT_ID。

    mysql> SELECT EVENT_ID, TRUNCATE(TIMER_WAIT/1000000000000,6) as Duration, SQL_TEXT
           FROM performance_schema.events_statements_history_long WHERE SQL_TEXT like '%10001%';
    +----------+----------+--------------------------------------------------------+
    | event_id | duration | sql_text                                               |
    +----------+----------+--------------------------------------------------------+
    |       31 | 0.028310 | SELECT * FROM employees.employees WHERE emp_no = 10001 |
    +----------+----------+--------------------------------------------------------+
    

    这一步类似于 SHOW PROFILES。

  • 执行如下SQL语句做性能分析,这样就可以知道这条语句各种阶段的信息了。

    mysql> SELECT event_name AS Stage, TRUNCATE(TIMER_WAIT/1000000000000,6) AS Duration
           FROM performance_schema.events_stages_history_long WHERE NESTING_EVENT_ID=31;
    +--------------------------------+----------+
    | Stage                          | Duration |
    +--------------------------------+----------+
    | stage/sql/starting             | 0.000080 |
    | stage/sql/checking permissions | 0.000005 |
    | stage/sql/Opening tables       | 0.027759 |
    | stage/sql/init                 | 0.000052 |
    | stage/sql/System lock          | 0.000009 |
    | stage/sql/optimizing           | 0.000006 |
    | stage/sql/statistics           | 0.000082 |
    | stage/sql/preparing            | 0.000008 |
    | stage/sql/executing            | 0.000000 |
    | stage/sql/Sending data         | 0.000017 |
    | stage/sql/end                  | 0.000001 |
    | stage/sql/query end            | 0.000004 |
    | stage/sql/closing tables       | 0.000006 |
    | stage/sql/freeing items        | 0.000272 |
    | stage/sql/cleaning up          | 0.000001 |
    +--------------------------------+----------+
    

OPTIMIZER_TRACE

我们再来聊一下分析SQL的另一款神器:OPTIMIZER_TRACE
翻译成中文叫做“优化器跟踪”。

它可以跟踪优化器做出各种决策,了解优化器的执行细节,进而帮助我们理解SQL的执行过程,并且优化SQL。

OPTIMIZER_TRACE是MySQL5.6引入的一项功能,此功能默认是关闭的,开启后,可分析如下语句:

  • SELECT
  • INSERT
  • REPLACE
  • UPDATE
  • DELETE
  • EXPLAIN
  • SET
  • DECLARE
  • CASE
  • IF
  • RETURN
  • CALL

OPTIMIZER_TRACE相关参数

参考 https://dev.mysql.com/doc/internals/en/system-variables-controlling-trace.html

  • –optimizer-trace
    • –optimizer-trace:总开关,默认值:enabled=off,one_line=off
    • enabled:是否开启optimizer_trace;on表示开启,off表示关闭。
    • one_line:是否开启单行存储。on表示开启;off表示关闭,将会用标准的JSON格式化存储。设置成on将会有良好的格式,设置成off可节省一些空间。
  • optimizer_trace_features
    • 控制optimizer_trace跟踪的内容,默认值:greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on,表示开启所有跟踪项。
    • greedy_search:是否跟踪贪心搜索,有关贪心算法详见:https://blog.csdn.net/qq_37763204/article/details/79289532
    • range_optimizer:是否跟踪范围优化器
    • dynamic_range:是否跟踪动态范围优化
    • repeated_subselect:是否跟踪子查询,如果设置成off,只跟踪第一条Item_subselect的执行
  • optimizer_trace_limit:控制optimizer_trace展示多少条结果,默认1
  • optimizer_trace_max_mem_size:optimizer_trace堆栈信息允许的最大内存,默认1048586
  • optimizer_trace_offset:第一个要展示的optimizer trace的偏移量,默认-1。
  • end_markers_in_json:如果JSON结构很大,则很难将右括号和左括号配对。为了帮助读者阅读,可将其设置成on,这样会在右括号附近加上注释,默认off。

以上参数可以用作SET语句操作,例如,用如下命令即可打开OPTIMIZER TRACE

SET OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on;

也可以用SET GLOBAL全局开启,但即使全局开启,每个Session也只能跟踪它自己执行的语句:

SET GLOBAL OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on

optimizer_trace_limit和optimizer_trace_offset这两个参数经常配合使用,例如:

SET optimizer_trace_offset=<OFFSET>,optimizer_trace_limit=<LIMIT>

这两个参数配合使用,有点类似MySQL里面的limit语句。
默认情况下,由于optimizer_trace_offset=-1,optimizer_trace_limit=1,记录最近的一条SQL语句,展示时,每次展示一条数据;

OPTIMIZER_TRACE使用

  1. 开启OPTIMIZER_TRACE功能,并设置要展示的数据条目数:
    SET OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on;
    SET optimizer_trace_offset=-30,optimizer_trace_limit=30;
    
  2. 发送你想要分析的查询语句,例如:
    select *
    from user_info 
    where nickname = 'Ant'
    and ctime > '2021-02-01'
    
  3. 使用如下语句分析,即可获得类似如下的结果:
    mysql> SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE limit 30 ;
    


其中QUERY这一列会展示出执行的sql是什么,TRACE则是Object的结果,它是一段很长的JSON,我把结果拷贝出来:

{
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `user_info`.`id` AS `id`,`user_info`.`username` AS `username`,`user_info`.`password` AS `password`,`user_info`.`real_name` AS `real_name`,`user_info`.`sex` AS `sex`,`user_info`.`birthday` AS `birthday`,`user_info`.`card_id` AS `card_id`,`user_info`.`mark` AS `mark`,`user_info`.`partner_id` AS `partner_id`,`user_info`.`group_id` AS `group_id`,`user_info`.`nickname` AS `nickname`,`user_info`.`avatar` AS `avatar`,`user_info`.`phone` AS `phone`,`user_info`.`add_ip` AS `add_ip`,`user_info`.`last_time` AS `last_time`,`user_info`.`last_ip` AS `last_ip`,`user_info`.`now_money` AS `now_money`,`user_info`.`brokerage_price` AS `brokerage_price`,`user_info`.`integral` AS `integral`,`user_info`.`sign_num` AS `sign_num`,`user_info`.`status` AS `status`,`user_info`.`level` AS `level`,`user_info`.`spread_uid` AS `spread_uid`,`user_info`.`spread_time` AS `spread_time`,`user_info`.`user_type` AS `user_type`,`user_info`.`is_promoter` AS `is_promoter`,`user_info`.`pay_count` AS `pay_count`,`user_info`.`spread_count` AS `spread_count`,`user_info`.`clean_time` AS `clean_time`,`user_info`.`addres` AS `addres`,`user_info`.`adminid` AS `adminid`,`user_info`.`login_type` AS `login_type`,`user_info`.`union_id` AS `union_id`,`user_info`.`open_id` AS `open_id`,`user_info`.`superior_user_id` AS `superior_user_id`,`user_info`.`is_indentor` AS `is_indentor`,`user_info`.`indentor_level_name` AS `indentor_level_name`,`user_info`.`direct_superior_user_id` AS `direct_superior_user_id`,`user_info`.`member_level_name` AS `member_level_name`,`user_info`.`upgrade_time` AS `upgrade_time`,`user_info`.`password_app` AS `password_app`,`user_info`.`store_name` AS `store_name`,`user_info`.`rank_indentor_id` AS `rank_indentor_id`,`user_info`.`rank_member_id` AS `rank_member_id`,`user_info`.`manage_pending` AS `manage_pending`,`user_info`.`manage_done` AS `manage_done`,`user_info`.`develop_pending` AS `develop_pending`,`user_info`.`develop_done` AS `develop_done`,`user_info`.`range_pending` AS `range_pending`,`user_info`.`range_done` AS `range_done`,`user_info`.`corpus_pending` AS `corpus_pending`,`user_info`.`corpus_done` AS `corpus_done`,`user_info`.`yeji_pending` AS `yeji_pending`,`user_info`.`yeji_done` AS `yeji_done`,`user_info`.`commission_pending` AS `commission_pending`,`user_info`.`commission_done` AS `commission_done`,`user_info`.`can_edit_material` AS `can_edit_material`,`user_info`.`poster_url` AS `poster_url`,`user_info`.`ctime` AS `ctime`,`user_info`.`mtime` AS `mtime`,`user_info`.`health_vip_ctime` AS `health_vip_ctime`,`user_info`.`makeup_vip_ctime` AS `makeup_vip_ctime`,`user_info`.`purchase_balance` AS `purchase_balance`,`user_info`.`ay_card_money` AS `ay_card_money`,`user_info`.`other_rank_id` AS `other_rank_id`,`user_info`.`superior_other_id` AS `superior_other_id`,`user_info`.`star_health_vip_ctime` AS `star_health_vip_ctime`,`user_info`.`star_makeup_vip_ctime` AS `star_makeup_vip_ctime`,`user_info`.`lock_money` AS `lock_money` from `user_info` where ((`user_info`.`nickname` = 'Ant') and (`user_info`.`ctime` > '2021-02-01'))"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "((`user_info`.`nickname` = 'Ant') and (`user_info`.`ctime` > '2021-02-01'))",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "((`user_info`.`nickname` = 'Ant') and (`user_info`.`ctime	

以上是关于一文道尽数据库底层原理,探讨Mysql调优之道的主要内容,如果未能解决你的问题,请参考以下文章

Spark性能调优之道——解决Spark数据倾斜(Data Skew)的N种姿势

mysql 性能调优之系统角度优化

spark记录SparkCore的调优之Spark内存模型

Spark学习之路 SparkCore的调优之Spark内存模型[转]

性能调优之5-Tomcat网络处理线程模型

性能调优之5-Tomcat网络处理线程模型