多表上的MySQL共享密钥
我正在尝试优化我的查询,我想我需要向驻留在三个不同表中的两个日期字段添加一个组合键 各表: PlayerJoin和PlayerLeave: 标高: MySQL查询:多表上的MySQL共享密钥,mysql,sql,optimization,key,Mysql,Sql,Optimization,Key,我正在尝试优化我的查询,我想我需要向驻留在三个不同表中的两个日期字段添加一个组合键 各表: PlayerJoin和PlayerLeave: 标高: 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.g
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
我需要做什么来优化查询
编辑:添加了一个示例数据。我想要的是,对于那些对重建查询感兴趣的人来说,非正式地说:
该数据库用于存储FPS射击游戏日志文件中的信息。
玩家可以加入或离开服务器。
服务器将平均每15-30分钟加载一个映射。
我想在关于玩家x的个人日志中只显示他实际玩过的地图。
更正式的说法是:我希望来自levelsloaded的所有行,对于这些行,玩家在加载level之前执行的最后一个操作“加入/离开”正在加入服务器。
注意:这只是形式化查询的一种方法,不需要坚持
我想要的SQLFIDLE的输出数据:
同样重要的是,查询需要快速。它应该能够现场使用,所以我的目标是响应时间不超过100毫秒,这与数据库大小无关。
如您所见,我确实使用了一个工作查询来提供我想要的输出数据,但是该查询在实时数据库上运行只需96秒,如果我去掉playerjoins和playerleaves之间的联合,甚至还需要2秒。我建议您将playerjoins和playerleaves表结合起来: 然后替换:
SELECT id, globalId, date, serverId, playerId, 'playerjoins' AS origin
FROM playerjoins pj WHERE playerId = 1)
UNION ALL
(SELECT id, globalId, date, serverId, playerId, 'playerleaves' AS origin
FROM playerleaves pl WHERE playerId = 1)
与
您的查询现在要短得多:
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.action, pjl.date AS pjldate
FROM playeraction pjl
JOIN levelsloaded ll ON pjl.date <= ll.date
WHERE playerId = 2224
) llbelow
LEFT OUTER JOIN (
SELECT ll.id, ll.globalId, pjl.date AS pjldate
FROM playeraction pjl
JOIN levelsloaded ll ON pjl.date <= ll.date
WHERE playerId = 2224
) 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 llbelow.action = 'J'
ORDER BY llbelow.date DESC, llbelow.pjldate DESC
如有必要,我们可以进一步简化。您能描述一下您想做什么吗?也许有更好的方法来表述您的查询。@GordonLinoff我正在尝试返回所有级别负载,对于这些级别负载,玩家加入或离开的最后一个操作是加入。如果您提供了示例数据和期望的结果,您将能够更好地解释您要做的事情。我相信有一种方法可以让你的查询写得不同,这样会更有效率。@GordonLinoff我会在有时间的时候尽快发布,我想只需要一个小时。不过,我正在深入考虑,要么让应用程序在插入数据库之前做更多的工作,要么切换到MariaDB之类的工具。@GordonLinoff根据请求添加了示例数据和所需内容。希望至少有人会看看,因为我花了很长时间才把问题的细节整理好。
+------+----------------+--------------+--------+-----------------+------------+-----------+-------+---------+------------+------------------------------------------------+
| "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 | "" |
+------+----------------+--------------+--------+-----------------+------------+-----------+-------+---------+------------+------------------------------------------------+
CREATE TABLE `playeraction` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`globalId` int(11) NOT NULL DEFAULT 1,
`date` datetime NOT NULL,
`serverId` int(11) NOT NULL,
`playerId` int(11) NOT NULL,
`action` char(1) NOT NULL DEFAULT 'J',
PRIMARY KEY (`id`),
KEY `globalId` (`globalId`),
KEY `date` (`date`),
KEY `serverId` (`serverId`),
KEY `playerId` (`playerId`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
SELECT id, globalId, date, serverId, playerId, 'playerjoins' AS origin
FROM playerjoins pj WHERE playerId = 1)
UNION ALL
(SELECT id, globalId, date, serverId, playerId, 'playerleaves' AS origin
FROM playerleaves pl WHERE playerId = 1)
SELECT id, globalId, date, serverId, playerId, action FROM playeraction
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.action, pjl.date AS pjldate
FROM playeraction pjl
JOIN levelsloaded ll ON pjl.date <= ll.date
WHERE playerId = 2224
) llbelow
LEFT OUTER JOIN (
SELECT ll.id, ll.globalId, pjl.date AS pjldate
FROM playeraction pjl
JOIN levelsloaded ll ON pjl.date <= ll.date
WHERE playerId = 2224
) 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 llbelow.action = 'J'
ORDER BY llbelow.date DESC, llbelow.pjldate DESC