我正在尝试对具有五百万行的表运行相对简单的查询。这只是我用来测试返回的值正确的一个小片段。问题在于此查询需要花费20分钟以上的时间才能完成,即使对于500,000条记录而言,这似乎也异常缓慢。
DROP VIEW IF EXISTS view_temp_sortie_stats;
CREATE VIEW view_temp_sortie_stats AS
SELECT server_id, session_id, ucid, role, sortie_id,
(
SELECT COUNT(sortie_id)
FROM raw_gameevents_log
WHERE sortie_id = l.sortie_id AND server_id = l.server_id AND session_id = l.session_id AND target_player_ucid = l.ucid AND event = "HIT"
) AS HitsReceived
FROM raw_gameevents_log l
WHERE ucid IS NOT NULL AND sortie_id IS NOT NULL
GROUP BY server_id, session_id, ucid, role, sortie_id;
SELECT * FROM view_temp_sortie_stats;
这是我的桌子:
接下来,我尝试为server_id,session_id,sortie_id添加索引以查看它是否会改进-这花费了超过10分钟的时间,并且超时。所以我无法添加它们。
这似乎异常缓慢,应该不需要花费太多时间来添加索引或执行此查询。
我的innodb_buffer_pool_size是5GB,但是运行这些查询时mysqld进程仅消耗300mb的内存。
我在具有12 GB Ram,2倍Intel Haswell CPU的Windows Server 2012 R2 Standard上运行,因此我应该从mysql那里看到比这更好的性能。
没有其他人连接到该MySql实例,并且没有其他操作发生。
有人知道出什么问题吗?
EDIT2 -部分修复
经过一番谷歌搜索后,我发现了为什么添加索引会永远占用-原始查询仍在后台运行了2个小时以上。一旦我杀死了查询,添加索引就花费了大约30秒。
现在,当我运行上面的查询时,它需要27秒-可以肯定的是,这是一个巨大的改进,但是对于500,000条记录而言,这仍然相当缓慢。这是新的查询说明计划:
答案 0 :(得分:1)
您的子查询是:
SELECT COUNT(sortie_id)
FROM raw_gameevents_log
WHERE sortie_id = l.sortie_id AND server_id = l.server_id
AND session_id = l.session_id AND target_player_ucid = l.ucid
AND event = "HIT"
,主要查询是:
SELECT server_id, session_id, ucid, role, sortie_id, [...]
FROM raw_gameevents_log l
WHERE ucid IS NOT NULL AND sortie_id IS NOT NULL
GROUP BY server_id, session_id, ucid, role, sortie_id;
让我们从子查询开始。 COUNT可以依靠任何东西,因此我们不必理会选择字段。 WHERE字段:
WHERE sortie_id = l.sortie_id AND server_id = l.server_id
AND session_id = l.session_id AND target_player_ucid = l.ucid
AND event = "HIT"
您创建一个从常量字段开始的索引,然后是其他字段:
CREATE INDEX subqindex ON raw_gameevents_log(
event,
sortie_id, server_id, session_id, target_player_ucid
)
然后是主要查询:
WHERE ucid IS NOT NULL AND sortie_id IS NOT NULL
GROUP BY server_id, session_id, ucid, role, sortie_id;
这里您需要一个索引
ucid, sortie_id, server_id, session_id, role
最后,您可以尝试摆脱子查询(即使优化器可能已经对此做了很好的工作):
SELECT server_id, session_id, ucid, role, sortie_id,
COALESCE(hits, 0) AS hits
FROM raw_gameevents_log l
LEFT JOIN
(
SELECT COUNT(1) AS hits FROM raw_gameevents_log
WHERE event = 'HIT'
) AS h
ON (h.sortie_id = l.sortie_id, h.server_id = l.server_id, h.session_id = l.session_id, h.target_player_ucid = l.ucid)
WHERE l.ucid IS NOT NULL AND l.sortie_id IS NOT NULL
GROUP BY l.server_id, l.session_id, l.ucid, l.role, l.sortie_id;