好的,我有一个我似乎无法优化的查询。也许我在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
提前致谢!
答案 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