【发布时间】:2013-12-16 19:11:36
【问题描述】:
我正在尝试优化我的查询,并且我认为我需要为位于三个不同表中的两个 date 字段添加一个组合键。
表格:
playerjoins 和playerleaves:
+------------+------------+--------+-------+-----------+------------------+
| "Field" | "Type" | "Null" | "Key" | "Default" | "Extra" |
+------------+------------+--------+-------+-----------+------------------+
| "id" | "int(11)" | "NO" | "PRI" | \N | "auto_increment" |
| "globalId" | "int(11)" | "NO" | "MUL" | \N | "" |
| "date" | "datetime" | "NO" | "MUL" | \N | "" |
| "serverId" | "int(11)" | "NO" | "MUL" | \N | "" |
| "playerId" | "int(11)" | "NO" | "MUL" | \N | "" |
+------------+------------+--------+-------+-----------+------------------+
levelsloaded:
+--------------+------------+--------+-------+-----------+------------------+
| "Field" | "Type" | "Null" | "Key" | "Default" | "Extra" |
+--------------+------------+--------+-------+-----------+------------------+
| "id" | "int(11)" | "NO" | "PRI" | \N | "auto_increment" |
| "globalId" | "int(11)" | "NO" | "MUL" | \N | "" |
| "date" | "datetime" | "NO" | "MUL" | \N | "" |
| "serverId" | "int(11)" | "NO" | "MUL" | \N | "" |
| "gamemodeId" | "int(11)" | "NO" | "MUL" | \N | "" |
| "mapId" | "int(11)" | "NO" | "MUL" | \N | "" |
+--------------+------------+--------+-------+-----------+------------------+
MySQL 查询:
SELECT llbelow.id, llbelow.globalId, llbelow.date, llbelow.serverId, llbelow.gamemodeId, llbelow.mapId
FROM (
SELECT ll.id, ll.globalId, ll.date, ll.serverId, ll.gamemodeId, ll.mapId, pjl.origin, pjl.date AS pjldate
FROM
(
(SELECT id, globalId, date, serverId, playerId, 'playerjoins' AS origin
FROM playerjoins pj WHERE playerId = 2224)
UNION ALL
(SELECT id, globalId, date, serverId, playerId, 'playerleaves' AS origin
FROM playerleaves pl WHERE playerId = 2224)
)
pjl
JOIN levelsloaded ll
ON pjl.date <= ll.date
) llbelow
LEFT OUTER JOIN (
SELECT ll.id, ll.globalId, pjl.date AS pjldate
FROM
(
(SELECT id, globalId, date, serverId, playerId, 'playerjoins' AS origin
FROM playerjoins pj WHERE playerId = 2224)
UNION ALL
(SELECT id, globalId, date, serverId, playerId, 'playerleaves' AS origin
FROM playerleaves pl WHERE playerId = 2224)
)
pjl
JOIN levelsloaded ll
ON pjl.date <= ll.date
) llbelow_inner
ON llbelow.id = llbelow_inner.id AND (llbelow.pjldate < llbelow_inner.pjldate OR (llbelow.pjldate = llbelow_inner.pjldate AND llbelow.globalId < llbelow_inner.globalId))
WHERE llbelow_inner.id IS NULL AND origin = 'playerjoins'
ORDER BY llbelow.date DESC, llbelow.pjldate DESC
查询的DESCRIBE:
+------+----------------+--------------+--------+-----------------+------------+-----------+-------+---------+------------+------------------------------------------------+
| "id" | "select_type" | "table" | "type" | "possible_keys" | "key" | "key_len" | "ref" | "rows" | "filtered" | "Extra" |
+------+----------------+--------------+--------+-----------------+------------+-----------+-------+---------+------------+------------------------------------------------+
| "1" | "PRIMARY" | "<derived2>" | "ALL" | \N | \N | \N | \N | "74494" | "100,00" | "Using where; Using temporary; Using filesort" |
| "1" | "PRIMARY" | "<derived5>" | "ALL" | \N | \N | \N | \N | "74494" | "100,00" | "Using where; Not exists" |
| "5" | "DERIVED" | "<derived6>" | "ALL" | \N | \N | \N | \N | "92" | "100,00" | "" |
| "5" | "DERIVED" | "ll" | "ALL" | "date" | \N | \N | \N | "1578" | "100,00" | "Using where; Using join buffer" |
| "6" | "DERIVED" | "pj" | "ref" | "playerId" | "playerId" | "4" | "" | "52" | "100,00" | "" |
| "7" | "UNION" | "pl" | "ref" | "playerId" | "playerId" | "4" | "" | "40" | "100,00" | "" |
| \N | "UNION RESULT" | "<union6,7>" | "ALL" | \N | \N | \N | \N | \N | \N | "" |
| "2" | "DERIVED" | "<derived3>" | "ALL" | \N | \N | \N | \N | "92" | "100,00" | "" |
| "2" | "DERIVED" | "ll" | "ALL" | "date" | \N | \N | \N | "1578" | "100,00" | "Using where; Using join buffer" |
| "3" | "DERIVED" | "pj" | "ref" | "playerId" | "playerId" | "4" | "" | "52" | "100,00" | "" |
| "4" | "UNION" | "pl" | "ref" | "playerId" | "playerId" | "4" | "" | "40" | "100,00" | "" |
| \N | "UNION RESULT" | "<union3,4>" | "ALL" | \N | \N | \N | \N | \N | \N | "" |
+------+----------------+--------------+--------+-----------------+------------+-----------+-------+---------+------------+------------------------------------------------+
我需要做什么来优化查询?
编辑:添加了带有示例数据的http://sqlfiddle.com/#!2/eb702/2。我想要的是以下内容,对于那些对重建查询感兴趣的人,非正式地说:
- 此数据库存储来自 FPS 射击游戏的日志文件中的信息。
- 玩家可以加入或离开服务器。
- 服务器平均每 15-30 分钟加载一次地图。
- 我想在关于玩家 x 的个人日志中只显示他实际玩过的地图。
更正式地说:我想要来自levelsloaded 的所有行,其中玩家在关卡加载之前执行的最后一个操作(加入/离开)是加入服务器。
(注:这只是形式化查询的一种方式,无需拘泥)
我想要的 SQLFiddle 输出数据:http://sqlfiddle.com/#!2/eb702/1
此外,重要的是,查询需要快速。它应该可以实时使用,所以我的目标是响应时间低于 100 毫秒,与数据库大小无关。
如您所见,我确实使用了一个工作查询来提供我想要的输出数据,但是该查询在实时数据库上运行了 96 秒,如果我摆脱 playerjoins 和 @987654334 之间的联合,甚至仍然需要 2 秒@。
【问题讨论】:
-
您能描述一下您要做什么吗?可能有更好的方法来制定您的查询。
-
@GordonLinoff 我正在尝试返回玩家所做的最后一个动作(加入或离开)正在加入的所有关卡负载。
-
。 .如果您提供样本数据和期望的结果,您将更好地解释您正在尝试做什么。我相信有一种方法可以以不同的方式编写您的查询,这样效率会更高。
-
@GordonLinoff 我会尽快发布它,我猜只有一个小时。我虽然在深入考虑让应用程序在插入数据库之前做更多的工作(虽然不容易),或者切换到 MariaDB 或其他东西。
-
@GordonLinoff 添加了示例数据,并根据要求添加。希望至少有人会看一看,因为我花了很长时间才把问题的详细信息放在一起。
标签: mysql sql optimization key