【问题标题】:Apply LIMIT And OFFSET Clauses In A MySQL Query To A Specific Table, When The Query Selects Data From Multiple Tables当查询从多个表中选择数据时,将 MySQL 查询中的 LIMIT 和 OFFSET 子句应用于特定表
【发布时间】:2022-12-10 18:20:09
【问题描述】:

我正处于设置一些功能以使用 PHP/MySQL 控制某些图像板组件的分页的早期阶段。

我最初需要做的是仅在查询的 boards 表部分设置 LIMITOFFSET 子句。这样我就可以按显示的板分页。

当输出此数据时,板上出现的图像(每个板 4 个预览图像)由 while 循环内的计数器控制,因此重要的是不要对这些图像应用 LIMIT 或 OFFSET。

数据是通过一个查询获取的,以防止对数据库进行嵌套的 MySQL 调用,这将是一个性能问题。

下面的 MySQL 中有 3 个表在起作用 - boards 表、images 表和 boards_images 表,它是一个具有多对多关系的数据透视表/链接表,用于存储图像分配给董事会。

问题

在下面的函数中,我将如何设置它以便 LIMITOFFSET 子句仅适用于 boards 表。如果我需要对数据进行分组,或者执行子查询,我无法确定,这两者我以前都没有做过,或者解决方案是否不是这两种方法?

function boardsOutput($limit=0, $offset=0) {

    $s = "SELECT boards.board_name, boards.board_id, boards.user_id, images.filename, images.image_title
    FROM boards
    LEFT JOIN boards_images ON boards_images.board_id = boards.board_id
    LEFT JOIN images        ON boards_images.image_id = images.image_id
    WHERE boards.user_id = :user_id
    ORDER BY boards.board_id DESC";

    // append the LIMIT and OFFSET values onto the query
    if($limit > 0) {
        $s.= " LIMIT " . $limit;
    }
    if($offset > 0) {
        $s.= " OFFSET " . $offset;
    }

    return $s;
}

// Provide values for the $limit and $offset arguments
$queryString = boardsOutput($limit, $offset);

// then add the $queryString variable to a PHP PDO prepare() method etc

输出板预览的屏幕截图。我想限制每页的数量

非常感谢任何帮助。

【问题讨论】:

  • 如果您对版块进行分页,您似乎只想从连接表中选择与版块匹配的图像。为什么要从其他表中选择所有内容?您是否查看了通过上述查询实际收到的数据?
  • @MarkusAO 还显示了用户的空板。他们可以创建一个空板,然后从图像库中向该板添加图像。用户将被限制在尚未确定数量的板上,这样事情就不会失控。
  • 如果你说你想使所有图像可用(在图像库中)到任何板,那么您应该只进行一个单独的查询来为您的图像库获取数据。 JOIN 会将连接表中的列合并为行,并且您应用的任何 LIMIT 都将应用于所有这些(复合)行。您可以想象制作一个 RIGHT JOIN 并应用一个 WHERE 过滤器来限制选择的板。也许不是。仅进行单独的简单查询以获取图像更容易且更便宜。
  • @MarkusAO 我不是这么说的。这些图像已经分配给 boards_images 表中的板(通过单独的过程),这是一个链接/透视多对多表。这方面都得到了照顾。这些是登录用户的看板预览,其中包含 4 张图像和特定的相关看板。如果您单击预览,它会将您带到完整的电路板,以便您可以查看该电路板的所有图像。
  • 然后我不清楚为什么你不想限制全部,如果你只想选择与正在显示的板相关的图像。

标签: php mysql


【解决方案1】:
SELECT ...
    FROM ( SELECT ... ORDER BY ... LIMIT .. OFFSET .. ) AS t1
    JOIN ... ON ...
    ORDER BY ...

在某些情况下,我建议将此作为对慢速查询的优化。通过限制(通过LIMITGROUP BYDISTINCT)“派生”表(t1)中的行数,查询的其余部分运行得更快。还有它可能可以更好地利用t1 中的复合索引。

我什至可以建议使用上述技术的另一种优化。 JOIN 回到原来的表格来挑选笨重的列(例如TEXTs),而不是拖着它们四处转转以便稍后过滤(通过LIMIT 等)。

OFFSET 是一种糟糕的分页方式。在简单的公式中,SQL 首先收集所有内容,然后排序,然后进行偏移+限制。或者,如果 INDEX 可以帮助 ORDER BY + LIMIT,则随着您向前翻页,查询运行会越来越慢。更多关于Pagination

上面的公式试图隔离子查询中 OFFSET 的痛苦。但是,在没有看到整个查询以及SHOW CREATE TABLE 的情况下,我不能说该技术有多有效。

JOIN 可能存在问题。如果 t1 中的每一行都“连接”到其他表中的零行或多于一行,则不能在派生表中使用 LIMIT——它会获取太多或太少的行。同样,我需要先看用例再说是否您的查询有这个问题。

LEFT JOIN t2... 允许您包含 t2 中缺失的行。 t2.* 中的任何一个都会得到 NULL。这个可能解决上面的“零”情况。

( SELECT GROUP_CONCAT(name) FROM pets ... ) AS pet_names 可用于处理上述“或更多”情况。这样,您就可以在一行中拥有宠物名字的共生主义者。它还处理“零”情况。

SELECT  kids.child_name,
        ( SELECT GROUP_CONCAT(name) FROM pets 
            WHERE kids.id = pets.owner_id ) AS pet_names
    FROM kids
    ORDER BY ...
    LIMIT ... OFFSET ...

现在你可以通过去掉OFFSET来进一步优化! 相反,在kids(基于ORDER BY)中“记住你离开的地方”。这在我上面的分页链接中有进一步讨论。

【讨论】:

  • 谢谢里克。就数量而言,用户可以拥有的板的绝对最大数量可能是 500,所以就大页码而言,我不太担心。不过,这个概念在网站的另一部分会有用——我还没有做的主图像库中的无限滚动。不过,我不确定我是否理解答案的第一部分,这与限制板表中的数字有何关系?
  • 提示:寻找图片的“延迟加载”。
  • 另一个提示:boards_images的索引:Many-to-many
  • 那么,对于最大的用户来说,这是大约 2000 张图像?一块板上可以有超过 4 张图片吗?您预计板数的限制是多少?
  • 是的,一块板可以有很多图像(总数尚未确定)。当用户单击预览(如图所示)时,会将他们带到该版块的版块页面。图像确实已经具有延迟加载(HTML 属性和 javascript 备份)。看板页面将无限滚动(直到看板的图像总数尚未确定,但可能是 500 张)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-26
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 1970-01-01
  • 2021-05-17
  • 2012-11-05
相关资源
最近更新 更多