代码之家  ›  专栏  ›  技术社区  ›  Omiod

选择最新记录时,选择要慢得多

  •  6
  • Omiod  · 技术社区  · 16 年前

    一个站点上会显示一个包含大约70k条记录的表,每页显示50条记录。 分页是用 limit offset,50 在查询中,可以在不同的列上对记录进行排序。

    浏览最新的页面(偏移量约为60000)会使查询速度比浏览第一页(约10倍)慢得多。

    这是使用 limit 命令? 有没有其他方法可以得到相同的结果?

    2 回复  |  直到 16 年前
        1
  •  7
  •   Quassnoi    16 年前

    偏移量大, MySQL 需要浏览更多记录。

    即使计划使用 filesort (这意味着应浏览所有记录), MySQL 优化它以便 $offset + $limit 对最上面的记录进行排序,这使得它对于 $offset .

    典型的解决方案是为要排序的列编制索引,记录列的最后一个值,然后在后续查询中重用它,如下所示:

    SELECT  *
    FROM    mytable
    ORDER BY
            value, id
    LIMIT 0, 10
    

    输出:

    value  id
    
    1      234
    3      57
    4      186
    5      457
    6      367
    8      681
    10     366
    13     26
    15     765
    17     345  -- this is the last one
    

    要进入下一页,请使用:

    SELECT  *
    FROM    mytable
    WHERE   (value, id) > (17, 345)
    ORDER BY
            value, id
    LIMIT 0, 10
    

    ,使用上的索引 (value, id) .

    当然,这对任意访问页面没有帮助,但对顺序浏览有帮助。

    也, MySQL 对于延迟行查找有某些问题。如果列已编入索引,则可能需要尝试这样重写查询:

    SELECT  *
    FROM    (
            SELECT  id
            FROM    mytable
            ORDER BY
                    value, id
            LIMIT   $offset, $limit
            ) q
    JOIN    mytable m
    ON      m.id = q.id
    

    有关详细解释,请参阅本文:

        2
  •  2
  •   ircmaxell    16 年前

    这就是MySQL处理限制的方式。如果它可以对索引进行排序(并且查询足够简单),则可以在找到第一个索引后停止搜索 offset + limit 排。所以 LIMIT 0,10 这意味着如果查询足够简单,它可能只需要扫描10行。但是 LIMIT 1000,10 意味着 在最低限度 它需要扫描1010行。当然,实际需要扫描的行数取决于许多其他因素。但这里的重点是越低 limit + offset ,需要扫描的行数的下限是…

    至于解决方法,我将优化您的查询,使查询本身不需要 LIMIT 子句尽可能有效。 EXPLAIN 在这种情况下你是朋友吗?