【发布时间】:2011-12-22 03:42:48
【问题描述】:
编辑:这是原始查询的简化版本(在 475K 行的产品表上运行 3.6 秒)
SELECT p.*, shop FROM products p JOIN
users u ON p.date >= u.prior_login and u.user_id = 22 JOIN
shops s ON p.shop_id = s.shop_id
ORDER BY shop, date, product_id;
这是解释计划
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE u const PRIMARY,prior_login,user_id PRIMARY 4 const 1 Using temporary; Using filesort
1 SIMPLE s ALL PRIMARY NULL NULL NULL 90
1 SIMPLE p ref shop_id,date,shop_id_2,shop_id_3 shop_id 4 bitt3n_minxa.s.shop_id 5338 Using where
瓶颈似乎是ORDER BY date,product_id。除去这两个排序,查询在 0.06 秒内运行。 (删除两者之一(但不是两者)几乎没有效果,查询仍然需要 3 秒以上。)我在 products 表中的 product_id 和 date 都有索引。我还在(产品,日期)上添加了一个索引,但没有任何改进。
newtover 认为问题在于 INNER JOIN users u1 ON products.date >= u1.prior_login 要求阻止使用 products.date 上的索引
已向我建议(不是来自此线程)在约 0.006 秒内执行的查询的两种变体(而不是原始的 3.6 秒)。
这个使用子查询,它似乎强制连接的顺序
SELECT p.*, shop
FROM
(
SELECT p.*
FROM products p
WHERE p.date >= (select prior_login FROM users where user_id = 22)
) as p
JOIN shops s
ON p.shop_id = s.shop_id
ORDER BY shop, date, product_id;
这个使用 WHERE 子句做同样的事情(虽然 SQL_SMALL_RESULT 的存在不会改变执行时间,没有它也是 0.006 秒)
SELECT SQL_SMALL_RESULT p . * , shop
FROM products p
INNER JOIN shops s ON p.shop_id = s.shop_id
WHERE p.date >= (
SELECT prior_login
FROM users
WHERE user_id =22 )
ORDER BY shop, DATE, product_id;
我的理解是,由于在将产品表连接到商店表之前减少了产品表的相关行数,这些查询的工作速度要快得多。我想知道这是否正确。
【问题讨论】:
-
顺便问一下,你需要在
circle_favorited上排序的多个product_id行是从哪里来的? -
@newtover 用户的多个朋友可以收藏同一个产品,因此每个喜欢具有给定 product_id 产品的不同朋友都会生成一个包含该 product_id(和朋友的用户名)的新行。收藏夹表中的每一行都包含一个 user_id 和一个二进制收藏夹值。如果此值为 0,则表示用户对产品投了反对票。如果此值为 1,则用户对产品投了赞成票。我按照 circle_favorited 进行排序,以便区分那些对产品投赞成票的用户和对它投反对票的用户。