我在MySQL中从未表现出良好的性能,而且我再次遇到了性能问题。
我正在尝试创建一个视图。相关部分是:
SELECT
c.customer_id,
....
IF (c.customer_id IN (
SELECT cn.customer_id FROM customer_notes cn
), 1, 0) AS has_notes
FROM customers c;
基本上,我只是想知道客户是否附有说明。多少笔记并不重要。如何使用JOIN重写它以加快速度?
customers表目前有150万行,因此性能问题。
答案 0 :(得分:1)
我认为EXISTS
比JOIN
或IN
更适合您的情况。
SELECT
IF (EXISTS (
SELECT *
FROM customer_notes cn
WHERE c.customer_id = cn.customer_id),
1, 0) AS filter_notes
FROM customers
答案 1 :(得分:1)
您是否需要选择客户ID?按照目前的情况,您是不是每个客户都运行一次子查询,并获得一个真值或假值的流,而不知道哪个适用于哪个客户?
如果这是您所需要的,您不需要引用customers表(除非您将数据库保持在语义不完整的状态,并且customer_notes中可能存在没有相应客户的条目 - 但是您比这个查询的性能有更大的问题);你可以简单地使用:
SELECT DISTINCT Customer_ID
FROM Customer_Notes
ORDER BY Customer_ID;
获取Customer_Notes表中至少有一个条目的客户ID值列表。
如果您需要客户ID值列表以及相关的真/假值,那么您需要进行连接:
SELECT C.Customer_ID,
CASE WHEN N.Have_Notes IS NULL THEN 0 ELSE 1 END AS Has_Notes
FROM Customers AS C
LEFT JOIN (SELECT Customer_ID, COUNT(*) AS Have_Notes
FROM Customer_Notes
GROUP BY Customer_ID) AS N
ON C.Customer_ID = N.Customer_ID
ORDER BY C.Customer_ID;
如果这会导致性能不佳,请检查您是否在Customer_Notes.Customer_ID上有索引。如果这不是问题,请研究查询计划。
在视图中无法做到
视图中允许的内容的小限制在任何DBMS中总是令人讨厌(MySQL并不是唯一有限制的)。但是,我们可以通过单个常规联接来完成。我刚想起来。 COUNT(column)
只计算非空值,如果所有值都为空则返回0,所以 - 如果你不介意计算而不是只计算0或1 - 你可以使用:
SELECT C.Customer_ID,
COUNT(N.Customer_ID) AS Num_Notes
FROM Customers AS C
LEFT JOIN Customer_Notes AS N
ON C.Customer_ID = N.Customer_ID
GROUP BY C.Customer_ID
ORDER BY C.Customer_ID;
如果你绝对必须有0或1:
SELECT C.Customer_ID,
CASE WHEN COUNT(N.Customer_ID) = 0 THEN 0 ELSE 1 END AS Has_Notes
FROM Customers AS C
LEFT JOIN Customer_Notes AS N
ON C.Customer_ID = N.Customer_ID
GROUP BY C.Customer_ID
ORDER BY C.Customer_ID;
请注意,使用'N.Customer_ID'是至关重要的 - 虽然表中的任何列都可以(但你没有泄露任何其他列的名称,AFAICR),我通常使用的不是加入专栏以获得清晰度。
答案 2 :(得分:0)
试试这个
SELECT
CASE WHEN cn.customer_id IS NOT NULL THEN 1
ELSE 0
END AS filter_notes
FROM customers c LEFT JOIN customer_notes cn
ON c.customer_id= cn.customer_id