2013-05-30 1 views
1

Веб-страница должна отображать одно изображение продукта для определенной категории продукта из базы данных PostgreSql. Это изображение должно автоматически изменяться на другое изображение каждые 25 секунд. Возвращенный продукт может быть случайным или в некоторой последовательности. Некоторый продукт может отсутствовать, а некоторые повторяются, но большинство продуктов в критериях должны возвращаться. Суммарное количество доступных изображений может меняться незначительно в зависимости от образца.Как вернуть строку образца из базы данных по одному

Используется код ниже, который выполняется через каждые 25 секунд. Для этого требуется два запроса к базе данных: один для подсчета, который может быть slwo и вторым для для получения одного изображения. В обоих случаях, когда предложения дублируются, в реальном приложении, где предложение очень велико, и его изменение требует изменений в двух местах.

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

ASP.NET/Mono MVC3, npgsql.

$count = select count(*) 
     from products 
     where prodtype=$sometype and productid in (select productid from images); 

$random = next random integer between 0 .. $count-1; 

-- $productsample is result: desired sample product 
$productsample = select product 
      from products 
      where prodtype=$sometype and productid in (select productid from images) 
      offset $random 
      limit 1; 


create table products (productid char(20) primary key, 
    prodtype char(10) references producttype 
); 

create table images(
id serial primary key, 
productid char(20) references products, 
mainimage bool 
); 

ответ

2

order by всегда будет дорого особенно, если выражение в порядке не индексируется. Так что не заказывайте. Вместо этого сделайте случайное смещение в count(), как в ваших запросах, но сделайте все сразу.

with t as (
    select * 
    from 
     products p 
     inner join 
     images i using (productid) 
    where 
     prodtype = $sometype 
) 
select * 
from t 
offset floor(random() * (select count(*) from t)) 
limit 1 

Эта версия может быть быстрее

with t as (
    select *, count(*) over() total 
    from 
     products p 
     inner join 
     images i using (productid) 
    where 
     prodtype = $sometype 
) 
select * 
from t 
offset floor(random() * (select total from t limit 1)) 
limit 1 
0

PosgreSQL:

SELECT column FROM table 
ORDER BY RANDOM() 
LIMIT 1 

Это дает один, случайный ряд. Вы можете, конечно, добавить обратно в свой WHERE-фильтр, чтобы убедиться, что это подходящая категория.

Это снимает ваше требование, чтобы сделать счет первым; а также имеет преимущество, позволяя движку базы данных делать выбор, уменьшая круглые поездки.

Примечание: Для людей, которые ищут способы, чтобы сделать это в других SQL двигателей: http://www.petefreitag.com/item/466.cfm

+0

спасибо. Ссылка в ответ описывает, что это дорого: он будет извлекать все строки и сортировать в памяти. Если это самый эффективный способ в PostgreSql? – Andrus

Смежные вопросы