我在包含超过300,000,000(是,3亿)行的数据库的PHP脚本中使用以下MySQL查询。我知道这是非常耗费资源的,运行这一个查询需要很长时间。有谁知道如何优化查询或以更快的方式获取信息?
我需要能够使用1到15之间的任何整数代替MID()中的14。我还需要能够匹配LIKE
子句中相同范围内的长度字符串。
表格信息:
games | longint, unsigned, Primary Key
win | bit(1)
loss | bit(1)
示例查询:
SELECT MID(`game`,14,1) AS `move`,
COUNT(*) AS `games`,
SUM(`win`) AS `wins`,
SUM(`loss`) AS `losses`
FROM `games`
WHERE `game` LIKE '1112223334%'
GROUP BY MID(`game`,1,14)
提前感谢您的帮助!
答案 0 :(得分:5)
首先,在游戏领域有一个索引...... :)
查询看似简单明了,但它隐藏了可能需要更改数据库设计的事实。
在这种情况下,我总是喜欢维护一个包含聚合数据的字段,每天,每个用户或每个任意轴。这样,您就可以拥有聚合相关数据的日常任务,并将其保存在数据库中。
如果确实经常调用此查询,则应使用降低插入效率的原则来提高检索效率。
答案 1 :(得分:2)
看起来game
列存储了此查询正在使用的两个(或可能更多)不同的内容:
game
开头过滤(前10个字符)MID(
游戏,1,14)
(我假设其中一个MID
表达式是拼写错误。我将其拆分,以便您不必在game
列上使用字符串操作,并且还将索引放在新列上,以便您可以对它们进行过滤和分组。
这个查询正在进行大量的转换(长到字符串)和字符串操作,如果表被规范化(如每列中的一条信息而不是像现在这样的多条信息),则不需要。
保留game
列的方式,并根据它创建一个game_filter
字符串列,以便在WHERE子句中使用。然后设置game_group
列,并在插入时使用MID
表达式填充它。将这两列设置为聚集索引,先是game_filter
,然后是game_group
。
答案 2 :(得分:1)
查询很简单,除了确保有所有必要的索引(显然是“游戏”字段)之外,通过仅重写查询可能没有明显的方法使其更快。 可能需要对数据结构进行一些修改。
一种方法:预先计算总和。这些记录中的每一个都很可能具有create_date或自动增量的键字段。预先计算所有记录的总和,此字段≤X,将结果放入边表,然后您只需计算所有记录> X,然后用预先计算的结果总结这些部分结果。
答案 3 :(得分:1)
您可以预先计算MID(game
,14,1)和MID(game
,1,14),并将game
的前十位数存储在单独的gameid列中这是索引。
调查是否可以只存储预先计算的值的聚合表,以便在插入时增加计数和赢或输列列,这也是一个想法。
答案 4 :(得分:0)
SELECT MID(`game`,14,1) AS `move`,
COUNT(*) AS `games`,
SUM(`win`) AS `wins`,
SUM(`loss`) AS `losses`
FROM `games`
WHERE `game` LIKE '1112223334%'
在game
上创建索引:
CREATE INDEX ix_games_game ON games (game)
并将此查询重写为:
SELECT move,
(
SELECT COUNT(*)
FROM games
WHERE game >= move
AND game < CONCAT(SUBSTRING(move, 1, 13), CHR(ASCII(SUBSTRING(move, 14, 1)) + 1))
),
(
SELECT SUM(win)
FROM games
WHERE game >= move
AND game < CONCAT(SUBSTRING(move, 1, 13), CHR(ASCII(SUBSTRING(move, 14, 1)) + 1))
),
(
SELECT SUM(lose)
FROM games
WHERE game >= move
AND game < CONCAT(SUBSTRING(move, 1, 13), CHR(ASCII(SUBSTRING(move, 14, 1)) + 1))
)
FROM (
SELECT DISTINCT SUBSTRING(q.game, 1, 14) AS move
FROM games
WHERE game LIKE '1112223334%'
) q
这将有助于更有效地使用game
上的索引。
答案 5 :(得分:0)
您可以使用Memcache或类似的东西缓存结果集吗?这将有助于重复点击。即使您只将结果集缓存几秒钟,也可以避免大量数据库读取。