Web page should show one product image for specific product category from PostgreSql database. This image should changed automatically to other image after every 25 seconds. Returned product may be random or in some sequence. Some product may be missing and some repeated but most of the products in criteria should returned. Total available image count may change slightly between sample retrieval
Currently code below is used which is executed after every 25 seconds. This requires two queries to database: one for count which may be slwo and second for single image retrieval. In both cases where clauses are duplicated, in real application where clause is very big and changing it requires changes in two places.
How to improve this so that single query returns sample ? Column types cannot changed, natural primary keys are used. Additional columns, triggers, indexes, sequences can added if this helps.
ASP.NET/Mono MVC3 , npgsql are used.
$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
);
An order by
will always be expensive specially if the expression in the order by is not indexed. So don't order. In instead do a random offset in the count()
as in your queries, but do it all at once.
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
This version might be faster
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
PosgreSQL:
SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1
This gives you one, random row. You can of course add back in your WHERE filter to make sure it is the right category.
This removes your requirement to do a count first; and also has the advantage of letting the database engine do the selection, reducing round trips.
Note: For people looking at ways to do this in other SQL engines: http://www.petefreitag.com/item/466.cfm
来源:https://stackoverflow.com/questions/16839881/how-to-return-sample-row-from-database-one-by-one