SQL возвращает строки в "циклическом" порядке - PullRequest
8 голосов
/ 21 июля 2009

У меня есть куча URL-адресов, которые хранятся в таблице и ждут, чтобы ее просмотрел скрипт. Тем не менее, многие из этих URL-адресов с одного сайта. Я хотел бы вернуть эти URL-адреса в «дружественном к сайту» порядке (т. Е. Стараться избегать двух URL-адресов с одного и того же сайта подряд), чтобы меня не случайно заблокировали, сделав слишком много http-запросов за короткое время. .

Структура базы данных выглядит примерно так:

create table urls (
    site varchar,       -- holds e.g. www.example.com or stockoverflow.com
    url varchar unique
);

Пример результата:

SELECT url FROM urls ORDER BY mysterious_round_robin_function(site);

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", но я понятия не имею, как написать что-то подобное.

Ответы [ 5 ]

4 голосов
/ 21 июля 2009

См. Эту статью в моем блоге для более подробного объяснения того, как это работает:

С новым 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

, хотя это может быть менее эффективно.

3 голосов
/ 21 июля 2009

Я думаю, вы слишком усложняете это. Почему бы просто не использовать

ЗАКАЗАТЬ ПО NewID ()

2 голосов
/ 21 июля 2009

Вы спрашиваете о круговом приеме, но я думаю, что простой

SELECT site, url FROM urls ORDER BY RANDOM()

сделает свое дело. Это должно работать, даже если URL-адреса с того же сайта кластеризованы в БД.

0 голосов
/ 27 июля 2009

Существует гораздо более простое и быстрое решение ...

  • добавить столбец sort_order типа TEXT
  • добавить триггер ON INSERT, который устанавливает sort_order равным md5 (url)
  • индекс по порядку сортировки
  • захватить строки в (sort_order, первичный ключ) порядке

-> это очень быстро и индексируется -> строки появятся в повторяемом, но случайном порядке

0 голосов
/ 21 июля 2009

Если URL-адреса меняются не очень часто, вы можете придумать несколько сложную работу, которую вы могли бы запускать периодически (по ночам?), Которая бы присваивала целые числа каждой записи на основе различных сайтов.

Что вы можете сделать, это написать процедуру, которая анализирует домен по URL-адресу (вы должны найти фрагмент кода, который делает это практически везде).

Затем вы создаете временную таблицу, которая содержит каждый уникальный домен плюс номер.

Затем для каждой записи в таблице URL-адресов вы просматриваете домен в своей временной таблице, присваиваете этой записи номер, сохраненный там, и добавляете большое число к номеру этой временной таблицы.

Затем для оставшейся части дня сортируйте по номеру.


Вот пример с пятью записями, которые вы использовали в своем вопросе:

URL-адрес:

Временная таблица:

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

Затем для каждого URL вы просматриваете значение во временной таблице и добавляете к нему 3 (потому что у него есть 3 различные записи):

Итерация 1:

URL-адрес:

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:

URL-адрес:

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

и так далее, пока не дойдете до

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

Для многих записей это будет медленно. И будет трудно работать со многими вставками / удалениями, но результатом будет безупречный порядок циклического перебора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...