这是一个奇怪的问题,所以问一个最好的方法就是举个例子。我有一份客户名单。我希望任何在CourseHistory
表或Access
表(或两者)中都有相应条目的客户。
我想要获取这些客户的最佳单个查询(无子查询)。我想出了
SELECT
c.cusid
FROM
Customers c
CROSS JOIN Realms r
LEFT JOIN Course.CourseHistory ch ON (c.cusid = ch.cusid)
LEFT JOIN Access a ON (c.cusid = a.cusid AND r.realmid = a.realmid)
WHERE
realmname = 'Course'
AND COALESCE(chid, accid)
这有效,但速度明显很慢,可能是因为它必须对Customers
进行全面扫描。由于CourseHistory
或Access
可以为null且结果仍然有效,因此必须将它们保持连接状态。有没有更正确的方法来进行此查询?
答案 0 :(得分:4)
摆脱那个CROSS JOIN到Realms和INNER JOIN将该表改为Access。
SELECT
c.cusid
FROM
Customers c
LEFT JOIN Course.CourseHistory ch ON (c.cusid = ch.cusid)
LEFT JOIN Access a
INNER JOIN realms r
ON a.realmid = r.realmid
AND r.realmname = 'Course'
ON c.cusid = a.cusid
WHERE
COALESCE(chid, accid)
答案 1 :(得分:3)
这是您的原始查询
SELECT
c.cusid
FROM
Customers c
CROSS JOIN Realms r
LEFT JOIN Course.CourseHistory ch ON (c.cusid = ch.cusid)
LEFT JOIN Access a ON (c.cusid = a.cusid AND r.realmid = a.realmid)
WHERE
realmname = 'Course'
AND COALESCE(chid, accid)
;
从你的评论中,我现在意识到这一点
鉴于此路径,这里是重构的查询
SELECT r.cusid
FROM
(SELECT realmid FROM Realms WHERE realmname = 'Course') r
LEFT JOIN
(SELECT realmid,cusid,accid FROM Access) a ON r.realmid=a.realmid
LEFT JOIN
(SELECT cusid FROM Course.CourseHistory) ch ON a.cusid=ch.cusid
WHERE COALESCE(chid, accid);
您需要以下索引
ALTER TABLE Realms ADD INDEX realmname_realmid_ndx (realmname,realmid);
ALTER TABLE Access ADD INDEX realmid_cusid_accid_ndx (realmid,cusid,accid);
试一试!!!
答案 2 :(得分:1)
您当前的查询以Customers x Realms
的笛卡尔积开头,并且应该返回太多重复项。如果每个客户拥有多条记录,那么Course.CourseHistory
和Access
上的联接也应该有很多重复项。
以下查询应该更有效。查询中的UNION
应用隐式DISTINCT
,即所有ID都是唯一的。此外,该查询允许MySQL优化器从表统计中受益,并以最佳顺序排列连接。
SELECT cuid
FROM Customers c
JOIN Course.CourseHistory ch USING (cuid)
UNION
SELECT cuid
FROM Realms r
JOIN Access a USING (realmid)
JOIN Customers c USING (cuid)
WHERE r.realmname = 'Course';
答案 3 :(得分:0)
您似乎想要从CourseHistory和Access(在“课程”领域内)收集所有客户ID,并检索与这些ID匹配的客户。这是一个完全相同的查询。
SELECT
c.cusid
FROM
Customers c
INNER JOIN (
SELECT ch.cusid FROM Course.CourseHistory AS ch
UNION
SELECT a.cusid FROM Access a
INNER JOIN Realms r ON r.realmid = a.realmid AND r.realmname = 'Course'
) AS ids ON c.cusid = ids.cusid
如果您确实只需要客户ID,并且保证客户表包含所有现有客户ID,那么您可以省去外部选择并只使用内部UNION。
如果你真的需要一个查询,那么你将不得不接受更糟糕的事情。这至少是对原始查询的改进:
SELECT
c.cusid
FROM
Customers c
LEFT JOIN Course.CourseHistory ch ON (c.cusid = ch.cusid)
LEFT JOIN Access a ON (c.cusid = a.cusid)
LEFT JOIN Realms r ON (r.realmid = a.realmid AND realmname = 'Course')
WHERE
AND chid IS NOT NULL OR realmname IS NOT NULL