【问题标题】:SQL return rows in a "round-robin" orderSQL以“循环”顺序返回行
【发布时间】:2023-03-20 23:25:01
【问题描述】:

我有一堆 URL 存储在一个表中等待被脚本抓取。但是,其中许多 URL 来自同一个站点。我想以“站点友好”的顺序返回这些 URL(即,尽量避免连续来自同一站点的两个 URL),这样我就不会在短时间内发出过多的 http 请求而被意外阻止.

数据库布局是这样的:

创建表 url (
    site varchar, -- 持有例如www.example.com 或 stockoverflow.com
    url varchar 唯一
);

示例结果:

从 url 中选择 url ORDER BY 神秘的round_robin_function(站点); http://www.example.com/some/file http://stackoverflow.com/questions/ask http://use.perl.org/ http://www.example.com/some/other/file http://stackoverflow.com/tags

我想到了像“ORDER BY site <> @last_site DESC”这样的东西,但我不知道如何写这样的东西。

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    有关其工作原理的更详细说明,请参阅我的博客中的这篇文章:

    有了新的PostgreSQL 8.4

    SELECT  *
    FROM    (
            SELECT  site, url, ROW_NUMBER() OVER (PARTITION BY site ORDER BY url) AS rn
            FROM    urls
            )
    ORDER BY
            rn, site
    

    旧版本:

    SELECT  site,
            (
            SELECT  url
            FROM    urls ui
            WHERE   ui.site = sites.site
            ORDER BY
                    url
            OFFSET  total
            LIMIT   1
            ) AS url
    FROM    ( 
            SELECT  site, generate_series(0, cnt - 1) AS total
            FROM    (
                    SELECT  site, COUNT(*) AS cnt
                    FROM    urls
                    GROUP BY
                            site
                    ) s
            ) sites
    ORDER BY
            total, site
    

    ,虽然它可能效率较低。

    【讨论】:

    • 如果你的表很大,最后一个查询真的需要检查效率。
    • 谢谢,它工作得很好!对我来说看起来像巫术,但总有一天我会弄明白的。
    • 我仍在使用 8.3,但该表目前只有 ~150 行。
    • @hhaamu:注意最后一次查询的查询时间会成倍增长。我会测试您计划达到的最大记录数。
    • @Quassnoi:会的。非常怀疑会有1000行。并且查询不会经常运行(每天一次或更少)。
    【解决方案2】:

    我认为你过于复杂了。为什么不直接使用

    按 NewID() 排序

    【讨论】:

    • 不错!非常简单。
    • 和RANDOM()类似吗?如果是,那还不够好。有几个网站占表格的 10-30%。
    • @hhaamu:我认为你低估了 RANDOM 的力量:
    【解决方案3】:

    您要求的是循环,但我认为很简单

    SELECT site, url FROM urls ORDER BY RANDOM()
    

    会成功的。即使来自同一站点的 url 聚集在 db 中,它也应该可以工作。

    【讨论】:

      【解决方案4】:

      如果 URL 不经常更改,您可以想出一个稍微复杂的作业,您可以定期(每晚?)运行它,它会根据存在的不同站点为每条记录分配整数。

      您可以做的是编写一个从 URL 解析域的例程(您应该能够找到几乎在任何地方执行此操作的 sn-p)。

      然后,您创建一个临时表,其中包含每个唯一域以及一个数字。

      然后,对于您的 URLs 表中的每条记录,您在临时表中查找域,为该记录分配存储在那里的编号,并将一个大数字添加到该临时表的编号。

      然后在当天剩下的时间里,按数字排序。


      这是您在问题中使用的五条记录的示例:

      网址:

      临时表:

      example.com       1
      stackoverflow.com 2
      perl.org          3
      

      然后对于每个 URL,您在 temp 表中查找值,并将 3 添加到它(因为它有 3 条不同的记录):

      迭代 1:

      网址:

      http://www.example.com/some/file         1
      http://www.example.com/some/other/file   NULL
      https://stackoverflow.com/questions/ask   NULL
      https://stackoverflow.com/tags            NULL
      http://use.perl.org/                     NULL
      

      临时表:

      example.com       4
      stackoverflow.com 2
      perl.org          3
      

      迭代 2:

      网址:

      http://www.example.com/some/file         1
      http://www.example.com/some/other/file   4
      https://stackoverflow.com/questions/ask   NULL
      https://stackoverflow.com/tags            NULL
      http://use.perl.org/                     NULL
      

      临时表:

      example.com       7
      stackoverflow.com 2
      perl.org          3
      

      等等,直到你到达​​p>

      http://www.example.com/some/file         1
      http://www.example.com/some/other/file   4
      https://stackoverflow.com/questions/ask   2
      https://stackoverflow.com/tags            5
      http://use.perl.org/                     3
      

      对于很多记录,它会很慢。并且很难处理许多插入/删除,但结果将是完美的循环排序。

      【讨论】:

        【解决方案5】:

        有一个更简单、更快的解决方案...

        • 添加一个 TEXT 类型的 sort_order 列
        • 添加一个 ON INSERT 触发器,将 sort_order 设置为 md5( url )
        • 排序顺序索引
        • 按(排序顺序,主键)顺序抓取行

        -> 它非常快并且被索引 -> 行将以可重复但随机的顺序出现

        【讨论】:

          猜你喜欢
          • 2012-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-11
          相关资源
          最近更新 更多