3

我有来自许多品牌的产品,用户可以收藏(多对多)并且用户可以关注品牌。对于主页,我需要用户添加到收藏夹的所有产品以及用户关注的品牌产品。

我附带了以下 SQL 查询,但是,它的工作方式与预期不同——它只返回来自关注品牌并且同时在收藏夹中的产品。

SELECT * FROM products
INNER JOIN favorites ON products.id = favorites.favorable_id
INNER JOIN followings ON products.merchant_id = followings.followable_id
WHERE favorites.favorable_type = 'Product' AND favorites.user_id = ?
AND followings.followable_type = 'Merchant' AND followings.user_id = ?

如何正确修复查询?提前致谢。

编辑:我将拥有 10k+ 产品,1k+ 用户。所以我需要最快的执行时间查询。

4

5 回答 5

3

一种“简单”的方法(只是修改您现有的查询)可能是将您的两个INNER JOINs 都变成LEFT JOINs 并at least one of the two joined successfullyWHERE子句中检查...

SELECT
  *
FROM
  products
LEFT JOIN
  favorites
    ON  products.id = favorites.favorable_id
    AND favorites.favorable_type = 'Product'
    AND favorites.user_id = ?
LEFT JOIN
  followings
    ON  products.merchant_id = followings.followable_id
    AND followings.followable_type = 'Merchant'
    AND followings.user_id = ?
WHERE
      favorites.user_id IS NOT NULL
  OR followings.user_id IS NOT NULL

这样做的缺点是表中的每条记录product都必须由WHERE子句检查。

如果该表很小,或者您通常以任何方式返回表的“大”部分,这可能没问题。但是,如果您只返回表的“一小部分”,您可能需要优化它,例如使用两个带有 的查询UNION,正如您的问题标题所暗示的那样......

SELECT
  products.*
FROM
  products
INNER JOIN
  favorites
    ON  products.id = favorites.favorable_id
    AND favorites.favorable_type = 'Product'
    AND favorites.user_id = ?

UNION

SELECT
  products.*
FROM
  products
INNER JOIN
  followings
    ON  products.merchant_id = followings.followable_id
    AND followings.followable_type = 'Merchant'
    AND followings.user_id = ?

由于可能能够在和上使用索引,因此此处的每个查询都INNER JOIN可能比整个基于查询的查询快得多。LEFT JOINfollowings(user_id, followable_type)favorites(user_id, favorable_type)

于 2013-09-12T09:04:16.053 回答
0

尝试更换

 INNER JOIN followings ON products.merchant_id = followings.followable_id

left JOIN followings ON favorites.favorable_id = followings.followable_id
于 2013-09-12T08:33:27.120 回答
0
select p.*
from products as p
where
    exists (
       select *
       from favorites as f
       where f.favorable_id = p.id and f.favorable_type = 'Product' and f.user_id = ?
    ) or
    exists (
       select *
       from followings as f
       where f.followable_id = p.merchant_id and f.followable_type = 'Merchant' and f.user_id = ?
    )
于 2013-09-12T08:51:58.250 回答
0
SELECT * FROM products p
LEFT JOIN favorites ON products.id = favorites.favorable_id and favorites.favorable_type = 'Product' AND favorites.user_id = ?
LEFT JOIN followings ON products.merchant_id = followings.followable_id and followings.followable_type = 'Merchant' AND followings.user_id = ?
WHERE favorites.user_id is not null or followings.user_id is not null
于 2013-09-12T08:57:10.660 回答
0

你可以试试这个:

select p.*
from products as p
where
p.id in (
       select f.favorable_id
       from favorites as f
       where  f.favorable_type = 'Product' and f.user_id = ?
)
or p.merchant_id in ( 
       select f.followable_id
       from followings as f
       where  f.followable_type = 'Merchant' and f.user_id = ?
)
于 2013-09-12T09:10:22.383 回答