postgres: получить случайные записи из таблицы - слишком медленно - PullRequest
1 голос
/ 28 ноября 2011

В моей базе данных postgres у меня есть следующие отношения (упрощенные ради этого вопроса):

Objects (currently has about 250,000 records)
-------
n_id
n_store_object_id (references store.n_id, 1-to-1 relationship, some objects don't have store records)
n_media_id (references media.n_id, 1-to-1 relationship, some objects don't have media records)

Store (currently has about 100,000 records)
-----
n_id
t_name,
t_description,
n_status,
t_tag

Media
-----
n_id
t_media_path

Пока все хорошо.Когда мне нужно запросить данные, я запускаю это (обратите внимание на limit 2 в конце как часть требования):

select
    o.n_id,
    s.t_name,
    s.t_description,
    me.t_media_path
from
    objects o
    join store s on (o.n_store_object_id = s.n_id and s.n_status > 0 and s.t_tag is not null)
    join media me on o.n_media_id = me.n_id
limit
    2

Это отлично работает и возвращает мне две записи, как и ожидалось.Время выполнения составляет около 20 мс - просто отлично.

Теперь мне нужно получать 2 случайные записи каждый раз, когда выполняется запрос.Я думал, что добавлю order by random(), вот так:

select
    o.n_id,
    s.t_name,
    s.t_description,
    me.t_media_path
from
    objects o
    join store s on (o.n_store_object_id = s.n_id and s.n_status > 0 and s.t_tag is not null)
    join media me on o.n_media_id = me.n_id
order by
    random()
limit
    2

Хотя это дает правильные результаты, время выполнения теперь составляет около 2500 мс (более 2 секунд).Это явно неприемлемо, так как это один из нескольких запросов, которые нужно запустить для получения данных для страницы в веб-приложении.

Итак, вопрос: как я могу получить случайные записи, как указано выше,но все же удерживайте время выполнения в течение некоторого разумного промежутка времени (т.е. для моей цели приемлемо менее 100 мс)?

Ответы [ 4 ]

3 голосов
/ 28 ноября 2011

Конечно, прежде чем получить первые строки, нужно отсортировать все по случайным критериям. Может быть, вы можете обойтись, используя random() в offset вместо?

1 голос
/ 29 ноября 2011

Вот несколько предыдущих работ по теме, которые могут оказаться полезными:

http://blog.rhodiumtoad.org.uk/2009/03/08/selecting-random-rows-from-a-table/

0 голосов
/ 28 ноября 2011

Кажется, что ваша проблема заключается в следующем: у вас есть таблица с 250000 строк и вам нужно две случайные строки. Таким образом, вы должны сгенерировать 250000 случайных чисел, а затем отсортировать строки по их номерам. Две секунды для этого кажутся мне довольно быстрыми.

Единственный реальный способ ускорить выбор - это не придумывать 250000 случайных чисел, а искать строки по индексу.

Я думаю, вам придется изменить схему таблицы, чтобы оптимизировать ее для этого случая. Как насчет чего-то вроде:

  • 1) Создайте новый столбец с последовательностью, начинающейся с 1.
  • 2) Каждый ряд будет иметь number.
  • 3) Создать индекс на: number % 1000
  • 4) Запрос строк, где number % 1000 равно случайному числу от 0 до 999 (это должно попасть в индекс и загрузить случайный часть вашей базы данных)
  • 5) Вероятно, затем вы можете добавить RANDOM () в предложение ORDER BY и затем он просто отсортирует этот кусок вашей базы данных и будет в 1000 раз быстрее.
  • 6) Затем выберите первые две из этих строк.

Если это все еще не достаточно случайно (поскольку строки всегда будут в паре, имеющие один и тот же «хэш»), вы, вероятно, можете сделать объединение двух случайных строк или иметь в предложении предложение OR и сгенерировать два случайных ключа. .

Надеюсь, что-то в этом роде может быть очень быстрым и достаточно случайным.

0 голосов
/ 28 ноября 2011

Я думаю, вам лучше сначала выбрать случайные объекты, а затем выполнить объединение этих объектов после того, как они будут выбраны. То есть, запрос один раз, чтобы выбрать случайные объекты, затем запрос снова, чтобы объединить только те объекты, которые были выбраны.

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