如何合并这两个左连接:http://sqlfiddle.com/#!9/1d2954/69/0
SELECT d.`id`, (adcount + bdcount)
FROM `docs` d
LEFT JOIN
(
SELECT da.`doc_id`, COUNT(da.`doc_id`) AS adcount FROM `docs_scod_a` da
INNER JOIN `scod_a` a ON a.`id` = da.`scod_a_id`
WHERE a.`ver_a` IN ('AA', 'AB')
GROUP BY da.`doc_id`
) ad ON ad.`doc_id` = d.`id`
LEFT JOIN
(
SELECT db.`doc_id`, COUNT(db.`doc_id`) AS bdcount FROM `docs_scod_b` db
INNER JOIN `scod_b` b ON b.`id` = db.`scod_b_id`
WHERE b.`ver_b` IN ('BA', 'BB')
GROUP BY db.`doc_id`
) bd ON bd.`doc_id` = d.`id`
是一个单一的左连接,只是为了简化它在我的代码中的使用,同时使它慢慢变慢?
答案 0 :(得分:1)
首先我要强调,你的计算方法是更好的方法。您有两个单独的维度,单独聚合它们通常是进行计算的最有效方法。它也是最具扩展性的方法。
那就是说,你的查询应该等同于这个版本:
SELECT d.id,
count(distinct a.id),
count(distinct b.id)
FROM docs d left join
docs_scod_a da
ON da.doc_id = d.id LEFT JOIN
scod_a a
ON a.id = da.scod_a_id AND a.ver_a IN ('AA', 'AB') LEFT JOIN
docs_scod_b db
ON db.doc_id = d.id LEFT JOIN
scod_b b
ON b.id = db.scod_b_id AND b.ver_b IN ('BA', 'BB')
GROUP BY d.id
ORDER BY d.id;
此查询比看起来更昂贵,因为与COUNT(DISTINCT)
相比,COUNT()
会产生额外的开销。
here是SQL小提琴。
并且,由于LEFT JOIN
可以返回NULL
值,因此您的查询更准确地写为:
SELECT d.`id`, COALESCE(adcount, 0) + COALESCE(bdcount, 0)
如果您遇到结果问题,这个小改动可能会解决这些问题。
答案 1 :(得分:1)
性能可能是一个大问题,具体取决于每个表的大小。它似乎是一种“膨胀 - 收缩”的情况,因为它首先通过JOIN
“膨胀”行数,然后通过GROUP BY
“缩小”。下面的表述避免了通货紧缩。
但首先,如果我正确地理解了这个子查询,那么
SELECT da.`doc_id`, COUNT(da.`doc_id`) AS adcount
FROM `docs_scod_a` da
INNER JOIN `scod_a` a ON a.`id` = da.`scod_a_id`
WHERE a.`ver_a` IN ('AA', 'AB')
GROUP BY da.`doc_id`
可以改写为
SELECT `doc_id`,
( SELECT COUNT(*)
FROM `scod_a`
WHERE `id` = da.`scod_a_id`
AND `ver_a` IN ('AA', 'AB')
) AS adcount
FROM `docs_scod_a` AS da
如果这是正确的,则整个查询变为
SELECT d.id,
( SELECT COUNT(*)
FROM docs_scod_a ds
JOIN scod_a s ON s.id = ds.scod_a_id
WHERE ds.doc_id = d.id
AND s.ver_a IN ('AA', 'AB')
) +
( SELECT COUNT(*)
FROM docs_scod_b ds
JOIN scod_b s ON s.id = ds.scod_b_id
WHERE ds.doc_id = d.id
AND s.ver_b IN ('BA', 'BB')
)
FROM docs AS d
哪些需要这些索引:
docs_scod_a: (doc_id, scod_a_id), (scod_a_id, doc_id)
docs_scod_b: (doc_id, scod_b_id), (scod_b_id, doc_id)
scod_a: (ver_a, id)
scod_b: (ver_b, id)
docs: -- presumably has PRIMARY KEY(id)
请注意缺少GROUP BY
。
docs_scod_a
闻起来像多对多映射表。我建议您按照提示here。
(不需要COALESCE
,因为COUNT
只会返回零。)
(我不知道我的版本是否比Gordon更好(更快或更好),也不知道我的索引是否有助于他的表达。)