为什么同一个查询在从 MySQL 服务器上的解释和执行与在主服务器上的解释和执行如此不同?

Why does the same query explain & perform so differently on a slave MySQL server than a master?

我有一个主 MySQL 服务器和一个从属服务器。数据在它们之间复制。

当我 运行 在 master 上查询时,它需要几个小时;在奴隶上需要几秒钟。 EXPLAIN 计划支持这一点——从服务器检查的行比主服务器少得多。

但是,由于这两个数据库中的结构和数据完全相同(或者至少应该相同),并且它们都运行使用相同版本的MySQL (5.5 .31 Enterprise),我不明白是什么原因造成的。

这与 this question(和其他人)的症状类似,但我不认为这是相同的根本原因,因为我的两台服务器通过 MySQL 复制同步,并且结构和数据内容(或应该)相同,并且 OS 和硬件资源在两台服务器上完全相同——它们是 VMWare,一个是另一个的映像。

我已验证每个 table 中的行数在两台服务器上完全相同,并且它们的配置相同(除了从服务器具有指向主服务器的指令)。没有通过数据本身来查看是否存在任何差异,我不确定我还能检查什么,如果有任何建议,我们将不胜感激。

查询是

 SELECT COUNT(DISTINCT(cds.company_id))
 FROM   jobsmanager.companies c
 ,      jobsmanager.company_jobsmanager_settings cjs
 ,      jobsmanager.company_details_snapshot cds
 ,      vacancies v
 WHERE  c.company_id = cjs.company_id
 AND    cds.company_id = c.company_id
 AND    cds.company_id = v.jobsmanager_company_id
 AND    cjs.is_post_a_job = 'Y'
 AND    cjs.can_access_jobsmanager = 'Y'
 AND    cjs.account_status != 'suspended'
 AND    v.last_live BETWEEN cds.record_date - INTERVAL 365 DAY AND cds.record_date
 AND    cds.record_date BETWEEN '2016-01-30' AND '2016-02-05';

大师是这样解释的,300万行在驱动table,没有key用法,花了一个多小时return结果:

+----+-------------+-------+--------+-------------------------+----------------+---------+---------------------------------+---------+--------------------------+
| id | select_type | table | type   | possible_keys           | key            | key_len | ref                             | rows    | Extra                    |
+----+-------------+-------+--------+-------------------------+----------------+---------+---------------------------------+---------+--------------------------+
|  1 | SIMPLE      | v     | ALL    | job_owner,last_live_idx | NULL           | NULL    | NULL                            | 3465433 |                          |
|  1 | SIMPLE      | c     | eq_ref | PRIMARY                 | PRIMARY        | 4       | s1jobs.v.jobsmanager_company_id |       1 | Using where; Using index |
|  1 | SIMPLE      | cds   | ref    | PRIMARY,company_id_idx  | company_id_idx | 4       | jobsmanager.c.company_id        |     538 | Using where              |
|  1 | SIMPLE      | cjs   | eq_ref | PRIMARY,qidx,qidx2      | PRIMARY        | 4       | jobsmanager.c.company_id        |       1 | Using where              |
+----+-------------+-------+--------+-------------------------+----------------+---------+---------------------------------+---------+--------------------------+

从服务器使用不同的驱动 table,使用索引,预测更像是检查了 310,000 行,并且 return 在几秒钟内得出结果:

+----+-------------+-------+--------+-------------------------+-----------+---------+----------------------------+--------+--------------------------+
| id | select_type | table | type   | possible_keys           | key       | key_len | ref                        | rows   | Extra                    |
+----+-------------+-------+--------+-------------------------+-----------+---------+----------------------------+--------+--------------------------+
|  1 | SIMPLE      | cds   | range  | PRIMARY,company_id_idx  | PRIMARY   | 3       | NULL                       | 310381 | Using where; Using index |
|  1 | SIMPLE      | c     | eq_ref | PRIMARY                 | PRIMARY   | 4       | jobsmanager.cds.company_id |      1 | Using index              |
|  1 | SIMPLE      | cjs   | eq_ref | PRIMARY,qidx,qidx2      | PRIMARY   | 4       | jobsmanager.c.company_id   |      1 | Using where              |
|  1 | SIMPLE      | v     | ref    | job_owner,last_live_idx | job_owner | 2       | jobsmanager.cds.company_id |     32 | Using where              |
+----+-------------+-------+--------+-------------------------+-----------+---------+----------------------------+--------+--------------------------+

我已经 运行 分析 TABLE、优化 TABLE 和修复 TABLE ...在两台服务器上快速尝试使它们保持一致,但没有运气.

作为临时解决方案,我可以 运行 从属服务器上查询,因为它们在 cron 脚本中,即使它们在从属服务器上花费很长时间,也不会增加主服务器的负载他们 运行 在 master 上时的方式。但是,我将不胜感激任何其他关于为什么这些不同的信息,或者我还能 check/revise 可以解释两者之间如此巨大差异的其他信息。我唯一能找到的是奴隶有更多的 free 内存,因为它很少使用;仅此一项就可以解释吗?如果不是还有什么?

$ ssh s1-mysql-01 free # master
             total       used       free     shared    buffers     cached
Mem:      99018464   98204624     813840          0     160752   55060632
-/+ buffers/cache:   42983240   56035224
Swap:      4095992    4095992          0
$ ssh s1-mysql-02 free # slave
             total       used       free     shared    buffers     cached
Mem:      99018464   80866420   18152044          0     224772   72575168
-/+ buffers/cache:    8066480   90951984
Swap:      4095992     206056    3889936
$

非常感谢。

这两个解释之间唯一真正大的区别是在 master 上没有索引用于空缺 table。

您可以尝试将 index hint(强制索引)放入 master 上的 select 以强制使用 job_owner 索引。

您也可以尝试 运行 analyze table 对主服务器上上述查询中涉及的所有 table 进行 运行 analyze table 以确保 table 和索引统计信息是正确的更新。