【问题标题】:Paginate items from different sources对来自不同来源的项目进行分页
【发布时间】:2019-04-09 02:47:16
【问题描述】:

这是我面临的一个问题:我需要列出一些项目。这些项目来自不同的来源(比如表 A、表 B、表 C),具有不同的属性和性质(尽管有些是常见的)。

如何将它们合并到一个分页列表中?

我考虑过的选项:

  • 首先获取它们,然后在代码中对它们进行排序和分页。这效果不好,因为项目太多(数千个)并且性能一团糟。

  • 使用共享属性将它们加入 SQL 视图,一旦 SQL 查询完成,仅重新加载分页项以获取其其余属性。到目前为止,这很有效,但如果源更改/增加,可能会变得难以维护。

你知道其他选择吗?基本上,从两个数据源(在 SQL 中或直接在代码中)对项目进行分页的最常用/推荐的方法是什么。

谢谢。

【问题讨论】:

  • 也许Union可以帮忙:dev.mysql.com/doc/refman/8.0/en/union.html
  • @MadhurBhaiya 这就是我为创建 SQL 视图所做的工作。 :)
  • 我认为你的问题是公平的。该视图将起作用,但如果行数增长很多,您需要考虑性能问题。您可能需要添加索引以使其更快,或者可能使用物化视图 (Flexviews)。
  • 您最关心的是什么?速度、数据库资源消耗、可维护性、调试?
  • @TheImpaler 用户的响应时间和开发人员的可维护性是我主要关心的问题。我会看看物化视图,谢谢!

标签: php mysql sql pagination mariadb


【解决方案1】:

如果UNION 解决了问题,这里有一些语法和优化提示。

这将提供 10 行页面中的第 21 页:

(
  ( SELECT ... LIMIT 210 )
  UNION  [ALL|DISTINCT]
  ( SELECT ... LIMIT 210 )
) ORDER BY ... LIMIT 10 OFFSET 200

请注意,210 = 200+10。您不能信任在内部 SELECTs 中使用 OFFSET

使用UNION ALL 来提高速度,但如果SELECTs 之间可能有重复的行,则明确说UNION DISTINCT

如果你去掉太多括号,你会得到语法错误或“错误”的结果。

如果您以子查询结尾,请重复 ORDER BY 而不是 LIMIT

SELECT ...
    FROM (
           ( SELECT ... LIMIT 210 )
           UNION  [ALL|DISTINCT]
           ( SELECT ... LIMIT 210 )
           ORDER BY ... LIMIT 10 OFFSET 200
         ) AS u
    JOIN something_else  ON ...
    ORDER BY ...

可能包含JOIN 的一个原因是为了提高性能——子查询u 将结果集简化为只有10 行,因此JOIN 将只有10 项要查找。将JOIN 放入内部会导致大量加入,然后减少到只有 10 个。

【讨论】:

  • 在您的评论中,您说不要担心视图等。是我不需要它还是我不应该这样做,因为它会使性能变得更糟?我说的是初学者大约 5,000 行,可以很快达到 100,000,但我怀疑它会不会超过这个数字。提前致谢。
  • @Jachinair - A VIEW 主要是底层SELECT 的语法糖;如果您愿意,请查看。制作一个物化视图需要你自己的努力;它在 MySQL 中不是自动化的;在这种情况下似乎不合适。
【解决方案2】:

实际上我最近不得不回答一个类似的情况,特别是跨两个大表进行报告并在它们之间进行分页。我得出的答案是使用子查询,如下所示:

SELECT
    t1.id as 't1_id',
    t1.name as 't1_name',
    t1.attribute as 't1_attribute',
    t2.id as 't2_id',
    t2.name as 't2_name',
    t2.attribute as 't2_attribute',
    l.attribute as 'l_attribute'
FROM (
    SELECT
        id, name, attribute
    FROM
        table1
    /* You can perform joins in here if you want, just make sure you're using your aliases right */
    /* You can also put where statements here */
    ORDER BY
        name DESC, id ASC
    LIMIT 0,50
    ) as t1
INNER JOIN (
    SELECT
        id,
        name,
        attribute
    FROM
        table2
    ORDER BY
        attribute ASC
    LIMIT 250,50
    ) as t2
    ON  t2.id IS NOT NULL
LEFT JOIN
    linkingTable as l
    ON  l.t1Id = t1.id
    AND l.t2Id = t2.id
/* Do your wheres and stuff here */
/* You shouldn't need to do any additional ordering or limiting */

【讨论】:

  • 另外请注意,有一些方法可以确保编译结果集的顺序优先于另一个可以很好地扩展的表。我没有包含它们,因为我不确定它是否在您想要做的范围内,但是如果您需要它们,请发表评论,我会编辑以包含它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-20
  • 1970-01-01
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多