Hi,
I have to implement a bestseller list feature into a shop software
and, unfortunately, I don't see a possibility to make it as fast as
it has to be.
The relevant stuff is distributed among four tables [1]. `orders`
contains all the ordered products. I use the following query to
create a per-category bestseller list:
SELECT SQL_NO_CACHE
COUNT(*) AS `bought`,
`a`.`article`
FROM
`orders` AS `a`
LEFT JOIN
`art2cat` AS `b`
ON
`a`.`article` = `b`.`article`
LEFT JOIN
`categories` AS `c`
ON
`b`.`category` = `c`.`id`
WHERE
`c`.`id` = '10'
AND
`a`.`date` > '2005-03-09 06:27:07'
GROUP BY
`a`.`article`
ORDER BY
`bought` DESC
LIMIT
8;
Then I use two SELECT statements and a UNION to make sure that I get
always as much bestsellers as requested even if no item has been
sold (the ids for the IN clause are from `a`.`article` from the
first query).
(
SELECT SQL_NO_CACHE
*
FROM
`articles`
WHERE
`id` IN (328, 1667, 494, 1557, 1003, 909, 1281, 193)
)
UNION
(
SELECT SQL_NO_CACHE
`a`.*
FROM
`articles` AS `a`
LEFT JOIN
`art2cat` AS `b`
ON
`a`.`id` = `b`.`article`
LEFT JOIN
`categories` AS `c`
ON
`b`.`category` = `c`.`id`
WHERE
`a`.`id` NOT IN (328, 1667, 494, 1557, 1003, 909, 1281, 193)
AND
`c`.`id` = '10'
LIMIT
2
);
The whole thing takes around 12 seconds to execute (1 mio rows in
`orders`, 10'000 rows in `articles`, 50 rows in `categories`, 10'000
rows in `art2cat`). The big problem is the first query with the
GROUP BY which causes a full table scan and has to be executed on
every request.
mysql> EXPLAIN SELECT ... \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: c
type: ref
possible_keys: id
key: id
key_len: 4
ref: const
rows: 1
Extra: Using where; Using index; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: a
type: ALL
possible_keys: date
key: NULL
key_len: NULL
ref: NULL
rows: 1000509
Extra: Using where
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: b
type: ref
possible_keys: article
key: article
key_len: 4
ref: test.a.article
rows: 1
Extra: Using where
3 rows in set (0.01 sec)
I already though about different approaches to avoid this.
- Use a counter in the article table so I could directly access the
most bought articles. Not possible, because I need to know which are
the bestsellers of the last week/last two weeks...
- 'Cache' the results in a temporary table (or something like that).
is senseless, 'cos I need to rebuild the bestseller list every few
requests. I can't let some people wait 15 seconds for the requested
page.
- Generate the bestseller list using some background job is
senseless too, 'cos I don't know what type of data is to be queried.
I would be very happy if somebody could give me a hint how to solve
this problem.
Regards,
A.
[1] http://sopic.com/test/tables.txt
P.S: MySQL 4.1, everything is InnoDB
--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe: http://lists.mysql.com/[EMAIL PROTECTED]