如何使用JOINED表和ORDER BY和OFFSET

时间:2017-11-23 12:33:21

标签: mysql optimization sql-order-by query-performance

games_releases是一个结合了游戏信息的表格。像游戏标题,游戏发行商或开发者这样的信息对于许多不同的游戏是相同的,因此它们被保存在不同的表格中,这些表格后来连接在一起。

以下示例仅加入games_titles表以便于理解(但实际上还有一些表按照相同的原则加入)。

games_releases表:

id            int(11)     <- unique
title_id      int(11)     <- index
developer_id  int(11)
... more game relevant data

games_releases的一些典型行看起来像:

id    title_id   developer_id   ...    ...
--------------------------------------------
1     17         265
2     23         41
3     31         3
4     42         15
5     17         123

games_titles表:

id      int(11)       <- unique
title   varchar(128)
created int(11)

games_titles的一些典型行看起来像:

id    title     created
----------------------------------------
17    Pac-Man   [some unix timestamp]   
23    Defender  [some unix timestamp]
31    Scramble  [some unix timestamp]
42    Q*bert    [some unix timestamp]
99    Phoenix   [some unix timestamp]

现在:假设用户希望按字母顺序查看所有游戏(一次24个),然后执行此查询......

SELECT
    id AS release_id, t.`title` AS title
FROM
    games_releases

LEFT JOIN games_titles t ON t.`id`=`games_releases`.`title_id`
ORDER BY title
LIMIT 24

这将被退回

release_id    title
-----------------------------
2             Defender
1             Pac-Man
5             Pac-Man
4             Q*Bert
3             Scramble

所以基本上结果表的特征是字符串而不是ID。

挑战:此查询将需要0.2秒才能运行,这是慢速的方式(games_releases列出了大约80.000项,但想象数据库增长到1.000.000项。)

以下是解释告诉我的内容(games_releases有索引title_id):

id select_type  table   partitions  type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  games_releases  NULL    index   NULL    title_id    4   NULL    76669   Using index; Using temporary; Using filesort
1   SIMPLE  t   NULL    eq_ref  PRIMARY PRIMARY 4   phoenix.games_releases.title_id 1

有机会对此进行优化吗?

编辑:问题已得到解答。问题是错误的“LEFT JOIN”而不是“JOIN”。

但是:我如何通过增长OFFSET来征服更长的执行时间?

虽然已经阅读了关于它的负载,但我很难理解在进行多个JOIN时如何有效地设置索引。

拥有games_titles的“标题”索引似乎没有任何效果。

1 个答案:

答案 0 :(得分:0)

供将来参考:有关查询效果的问题通常必须显示查询中涉及的每个表的SHOW CREATE TABLE tablename的输出。表结构对性能产生影响。

从您的查询中看,您希望按照字母顺序显示games_titles表格中的前24个标题,其中games_releases表格中存在任何匹配项。我不明白你LEFT JOIN的逻辑。如果games_releases中的标题有多行,您是否希望重复标题?对于games_releasesgames_titles行无法匹配的行,您想要做什么?

我认为你可以得到你想要的结果如下:

   SELECT DISTINCT t.id, t.title
     FROM games_titles t
     JOIN games_releases r ON t.id = r.title_id
    ORDER BY t.title
    LIMIT 24

这会从titles表中提供与releases表中的任何内容匹配的不同行。这可能是其性能的最佳选择。不过,我想知道,在您的应用程序中,按字母顺序排列前24个标题的重要性,以及为什么这对于放入视图很重要。

SELECT lots, of, stuff .... ORDER BY something LIMIT number是一个臭名昭着的性能反模式。为什么? MySQL必须对大量数据进行排序,只丢弃少量数据。视图定义的局限性使您难以在视图中更有效地执行某些操作。

您没有告诉我们games_titles.id是否被编入索引。它需要编入索引。如果它是主键,则将其编入索引。