0

我正在尝试运行此查询:

SELECT 
    COUNT(events.event_id) AS total_events,
    COUNT(matches.fight_id) AS total_matches,
    COUNT(players.fighter_id) AS total_players,
    COUNT(DISTINCT events.organization) AS total_organizations,
    COUNT(DISTINCT players.country) AS total_countries
FROM 
    events, matches, players

这些是表格详细信息:事件 = 21k 玩家 = 90k 比赛 = 155k

所有这些都是唯一的,因此查询的前三件事将是这些数字。其他两个值应该是 total_organizations,其中组织列在事件中(应该返回几百),total_countries 应该使用玩家表中的国家列计算不同的国家(也是几百)。

所有这三个 ID 列都是唯一的且已编入索引。

这个查询现在需要永远。我什至没有耐心看到它完成。有没有更快的方法来做到这一点?

另外,我需要在每次页面加载时加载这些结果,所以我应该将此查询放在某个隐藏文件中,并设置一个 cron 作业以在每个午夜或某事运行并填充“总计”表或其他内容,以便我可以检索它从那张桌子上快吗?

谢谢!

4

1 回答 1

1

首先,去掉这里不必要的join;它阻止了大多数(如果不是全部)索引被使用。您需要三个不同的查询:

SELECT 
    COUNT(events.event_id) AS total_events,
    COUNT(DISTINCT events.organization) AS total_organizations
FROM 
    events;

SELECT 
    COUNT(matches.fight_id) AS total_matches
FROM 
    matches;

SELECT 
    COUNT(players.fighter_id) AS total_players,
    COUNT(DISTINCT players.country) AS total_countries
FROM 
    players;

这应该对提高这些查询的性能大有帮助。

现在,考虑添加这些索引:

CREATE INDEX "events_organization" ON events (organization);
CREATE INDEX "players_country" ON events (country);

比较EXPLAIN SELECT ...添加这些索引前后的结果。他们可能会有所帮助,也可能不会。


请注意,如果您使用 InnoDB 存储引擎,那么无论如何都会访问所有表行,以强制执行事务隔离。在这种情况下,索引将仅用于确定要访问的表行。由于您正在计算整个表,因此根本不会使用索引。

如果您使用的是不完全支持 MVCC 的 MyISAM,那么COUNT()查询应该能够仅使用索引基数来执行,这将产生几乎即时的结果。这是可能的,因为 MyISAM 不支持事务,这意味着隔离不再是问题。

因此,如果您使用的是 InnoDB,那么您可能最终不得不使用 cronjob 来创建此数据的缓存。

于 2012-10-02T23:01:21.367 回答