我有一个可用的SELECT语句,并且在我的表上运行得足够快(对于50k +产品,3k +类别,<0.01秒)。但在我看来,它不是很优雅,并希望听到任何有关改善它的建议。
有3个感兴趣的表:
我有一个排除的类别ID列表[例如1040,1050,1168] 我想选择属于这些排除类别之一的所有产品ID 仅当产品不属于另一个不排除的类别时
我的查询如下所示:
SELECT DISTINCT productID
FROM products_tree
WHERE
categoryID IN (1040,1050,1168)
AND productID NOT IN
( SELECT DISTINCT productID
FROM products_tree
WHERE
categoryID NOT IN (1040,1050,1168)
);
答案 0 :(得分:1)
我可以想到一些方法,每种方法根据索引和特定的数据库实现执行不同的方法。一些可能看起来很慢的东西可以用你可能没有想到的方式进行优化,因此值得试试它们并比较执行计划以查看发生的事情......
注1:我使用GROUP BY而不是DISTINCT,这是因为它允许omptimiser使用索引。我已经看到实现可以将DISTINCT转换为GROUP BY,但是确保使用GROUP BY非常值得。它也让你思考索引,这从来都不是坏事。
注意2:像这样的一些查询需要一段时间才能进行优化,因为优化器有很多选项可供评估。因此,通常值得编译存储过程中的所有不同选项并比较这些存储过程的执行。这可以确保您实际比较查询时间而不是不同的编译时间。
SELECT
[tree].productID
FROM
products_tree AS [tree]
WHERE
[tree].productID IN (1040,1050,1168)
AND NOT EXISTS (SELECT * FROM products_tree WHERE productID = [tree].productID AND categoryID NOT IN (1040,1050,1168))
GROUP BY
[tree].productID
SELECT
[tree].productID
FROM
products_tree AS [tree]
LEFT OUTER JOIN
(
SELECT
productID
FROM
product_tree
WHERE
productID NOT IN (1040,1050,1168)
GROUP BY
productID
)
AS [ok_products]
ON [ok_products].productID = [tree].productID
WHERE
[tree].productID IN (1040,1050,1168)
AND [ok_products].productID IS NULL
GROUP BY
[tree].productID
SELECT
[tree].productID
FROM
products_tree AS [tree]
GROUP BY
[tree].productID
HAVING
MAX(CASE WHEN [tree].productID IN (1040,1050,1168) THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN [tree].productID NOT IN (1040,1050,1168) THEN 1 ELSE 0 END) = 0
还有其他的,各自的变化,但这应该给你一个很好的开始。但我真的会强调使用GROUP BY和对INDEXES的考虑:)
答案 1 :(得分:0)
我相信您的查询非常好,但您可以将其与联接进行比较:
SELECT DISTINCT pt1.productID FROM products_tree pt1 LEFT JOIN products_tree pt2 ON pt2.productID = pt1.productID AND pt2.categoryID pt1.categoryID WHERE pt1.categoryID IN (1040,1050,1168) AND pt2.productID IS NULL
不确定我是否正确,但我认为你了解我的做法。然而,如果你想要,我会直接选择productinfo,然后连接会更有意义(内连接你想要的类别,左连接你不想要的那些并检查为空)
答案 2 :(得分:0)
您可以尝试“NOT EXISTS”变体:
SELECT
pt.productID
FROM
products_tree pt
WHERE
pt.categoryID IN (1040,1050,1168)
AND NOT EXISTS (
SELECT 1
FROM products_tree
WHERE productID = pt.productID AND categoryID NOT IN (1040,1050,1168)
)
GROUP BY
pt.productID;