为什么同一个查询在从 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 和索引统计信息是正确的更新。
我有一个主 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 和索引统计信息是正确的更新。