查询性能问题。我可以优化吗?

时间:2011-10-05 20:31:21

标签: mysql

好的,我有一个我似乎无法优化的查询。也许我在MySQL中做得太多,应该委托给PHP更多。查询大约需要一分钟,但我真的需要它比这快得多。下面是一个假设的结构,可以让你了解我想要完成的任务。

您会注意到我正在为查询提供一个PHP变量$ bookList,其中包含当前用户以逗号分隔格式拥有的book_id列表。

对于此示例,假设用户将70个book_id分配给他的库($ bookList),并且他想知道哪些商店与他的库共享最多的书籍。每家商店有70本书,但有20多万家商店。共存少于50%的商店将被过滤掉。

表1:my_books

id: mediumint
book_id: smallint

表2:store_books

store_id: mediumint
book_id: smallint
index: store_id
index: book_id

表3;存储

id: mediumint
name: varchar(50)
primary: id

查询:

SELECT count(s.book_id) AS commonBooks, s.id
                 FROM store_books AS sb
                 INNER JOIN stores AS s ON s.id = sb.id
                 WHERE sb.book_id IN ($bookList) 
                 GROUP BY sb.store_id 
                 HAVING commonBooks > 35
                 ORDER BY commonBooks

提前致谢!

2 个答案:

答案 0 :(得分:2)

借用@Joe Stefanelli的回答,使用临时表 确保你在bl.book_id

上有主索引

BTW:您的查询中似乎有错误:

SELECT count(*) AS commonBooks, s.id
FROM store_books AS sb
INNER JOIN stores AS s ON s.id = sb.store_id  -- <<sb.store_id, not sb.id
WHERE sb.book_id IN (SELECT bl.book_id FROM tempBookList)
GROUP BY sb.store_id 
HAVING commonBooks > 35
ORDER BY commonBooks DESC

一个鲜为人知的事实是,MySQL每个(子)选择只能使用一个索引 确保表store_book中有一个综合索引 另外count(*) (有时)count(afield) 更快(并且从不慢)

Table 2: store_books

store_id: mediumint
book_id: smallint
index: (store_id, book_id)  <<-- composite primary index.
index: (book_id)

此查询在InnoDB中的运行速度比MyISAM快,因为InnoDB可以使用覆盖索引来解析此查询,而不需要读取实际表中的数据。

答案 1 :(得分:1)

就个人而言,我将$ bookList中的值提取到临时表中,并将IN替换为该临时表的JOIN。

SELECT count(s.book_id) AS commonBooks, s.id
                 FROM store_books AS sb
                 INNER JOIN stores AS s ON s.id = sb.id
                 INNER JOIN tempBookList AS bl ON sb.book_id = bl.book_id
                 GROUP BY sb.store_id 
                 HAVING commonBooks > 35
                 ORDER BY commonBooks