带有连接和子查询的 mysql 查询优化
Posted
技术标签:
【中文标题】带有连接和子查询的 mysql 查询优化【英文标题】:mysql query optimization with join and subquery 【发布时间】:2017-04-09 11:28:00 【问题描述】:有人可以帮忙吗?来自慢日志 下面的这个查询需要 11 秒才能运行并且它会占用服务器资源。如何重新编写此查询以实现更大的优化?
P.S: 表格已编入索引。
查询:
SELECT SUM(the_val) AS value
FROM
(SELECT DISTINCT basic_data.id,
att2.the_val
FROM province_create
INNER JOIN basic_data ON province_create.province = basic_data.province
INNER JOIN att2 ON att2.church_id = basic_data.id
WHERE province_create.block = 0
AND att2.month = 'Feb'
AND att2.year = '2017'
AND basic_data.parish = 1
AND att2.report = 'ATTENDANCE'
AND province_create.disable = 0 ) t1;
解释报告:
[1] => 数组 ( [0] => 1 [id] => 1 [1] => 初级 [select_type] => 初级 [2] => [表] => [3] => 全部 [类型] => 全部 [4] => [可能的键] => [5] => [关键] => [6] => [key_len] => [7] => [参考] => [8] => 38339 [行] => 38339 [9] => [额外] => )
[2] => Array
(
[0] => 2
[id] => 2
[1] => DERIVED
[select_type] => DERIVED
[2] => province_create
[table] => province_create
[3] => ALL
[type] => ALL
[4] => kk,province,kkk
[possible_keys] => kk,province,kkk
[5] =>
[key] =>
[6] =>
[key_len] =>
[7] =>
[ref] =>
[8] => 261
[rows] => 261
[9] => Using where; Using temporary
[Extra] => Using where; Using temporary
)
[3] => Array
(
[0] => 2
[id] => 2
[1] => DERIVED
[select_type] => DERIVED
[2] => basic_data
[table] => basic_data
[3] => ref
[type] => ref
[4] => PRIMARY,kk,kkk,k,parish
[possible_keys] => PRIMARY,kk,kkk,k,parish
[5] => kk
[key] => kk
[6] => 56
[key_len] => 56
[7] => databaseuser.province_create.province
[ref] => databaseuser.province_create.province
[8] => 39
[rows] => 39
[9] => Using index; Distinct
[Extra] => Using index; Distinct
)
[4] => Array
(
[0] => 2
[id] => 2
[1] => DERIVED
[select_type] => DERIVED
[2] => att2
[table] => att2
[3] => ref
[type] => ref
[4] => indpull,mmm
[possible_keys] => indpull,mmm
[5] => mmm
[key] => mmm
[6] => 57
[key_len] => 57
[7] => databaseuser.basic_data.id
[ref] => databaseuser.basic_data.id
[8] => 1
[rows] => 1
[9] => Using where; Distinct
[Extra] => Using where; Distinct
)
)
【问题讨论】:
(a) 涉及多少条记录? (b) 如果您在子查询中不包含basic_data.id
会有所不同吗?
请出示原始数据样本。为什么需要SELECT DISTINCT
?
@Manngo。 (a) Province_create 表——大约 300 条记录。 b
@uzor basic_data.id
是主键吗?在 SELECT DISTINCT
子句中包含主键通常没有多大意义,因为它已经不同了。另外,您真的希望att2.the_val
与众不同吗?我不知道该值的含义,但您排除了该值的多次出现。换句话说,为什么它们是不同的?
@Manngo (a)province_create 表 - 大约 300 条记录,basic_data 表大约 50,000 条记录,att2 表大约 200 万条记录。 (B) select distinct basic_data.id 是必需的,因为 att2 表上的一些 id 出现了不止一次。当我把它拿出来时,它给了我一个不同的(错误的)结果
【参考方案1】:
首先,让我假设不需要SELECT DISTINCT
。那么查询可以写成:
SELECT SUM(a.the_val)
FROM province_create pc INNER JOIN
basic_data bd
ON pc.province = bd.province INNER JOIN
att2 a
ON a.church_id = bd.id
WHERE pc.block = 0 AND
a.month = 'Feb' AND
a.year = '2017' AND
bd.parish = 1 AND
a.report = 'ATTENDANCE'
pc.disable = 0 ;
其次,您应该尝试在表上建立索引。很难说最好的索引是什么,所以尝试添加以下内容:
attr2(year, month, report, church_id, the_val)
basic_data(id, province, parish)
province_create(province, disable)
即使需要SELECT DISTINCT
,该索引也应该有所帮助。但是,您需要了解为什么会出现重复并解决该问题的根本原因以获得最佳性能。
【讨论】:
感谢它显着提高了性能。然而问题在于 att2 表上的 Church_id(它是 basic_data.id 的外键)不是唯一的。 (即,有时某个特定的 Church_id、月、年、报告会出现多次)。我从您的解决方案中获得的价值高于应有的价值。那么我如何(a)确保它不加倍或(b)有没有办法可以在att2表上搜索重复的值(基于basic_data.id)并删除它们?谢谢。感谢您的帮助 @uzor 。 . .该索引是否适用于您的原始查询? 是的,它适用于原始查询,但适用于您的解决方案。现在我正在研究删除 mysql 表中重复条目的方法,以便我可以采用您的解决方案。以上是关于带有连接和子查询的 mysql 查询优化的主要内容,如果未能解决你的问题,请参考以下文章