这是一个相对复杂问题的简化版本,我和我的同事们无法理解这些问题。
考虑两个表,table_a
和table_b
。在我们的CMS table_a
中保存了数据库中存储的所有数据的元数据,table_b
有一些更具体的信息,因此为简单起见,我需要title
和date
列。
目前我们的查询如下:
SELECT *
FROM `table_a` LEFT OUTER JOIN `table_b` ON (table_a.id = table_b.id)
WHERE table_a.col = 'value'
ORDER BY table_b.date ASC
LIMIT 0,20
当table_a
有大量行时,这会严重降低。如果更改JOIN RIGHT OUTER JOIN
(触发MySQL使用table_b.date
上的INDEX集),查询会无限快,但它不会产生相同的结果(因为如果table_b.date
没有值,它被忽略了。)
这在我们的CMS中成为一个问题,因为如果用户对日期列进行排序,那么任何没有设置日期的行都会从界面中消失,从而产生令人困惑的UI体验并且难以为日期添加日期缺少它们的行。
是否有解决方案:
table_b
。date的INDEX这样做
查询将更好地扩展table_b
没有date
的{{1}}
设置,以便用户可以输入
数据答案 0 :(得分:0)
我将参加第二次ArtoAle的评论。由于order by
适用于table_b
中缺失行的外部联接中的空值,因此无论如何这些行都将无序。
模拟的外连接是丑陋的部分,所以让我们先看一下。 Mysql没有except
,所以你需要用exists
来编写查询。
SELECT table_a.col1, table_a.col2, table_a.col3, ... NULL as table_b_col1, NULL as ...
FROM
table_a
WHERE
NOT EXISTS (SELECT 1 FROM table_a INNER JOIN table_b ON table_a.id = table_b.id);
应将原始查询UNION ALL
作为内部联接。{p>需要UNION_ALL
才能保留原始订单。
无论你做什么,这种查询都可能会变慢,因为没有一个索引可以轻易支持“外键不存在”的查询类型。这基本上归结为table_a.id中的索引扫描,其中table_b.id中的相应行具有查找(或者可能是并行扫描)。
答案 1 :(得分:0)
所以我们最终实现了一个不同的解决方案,虽然结果不如使用INDEX,但它仍然提供了大约25%的快速提升。
我们删除了JOIN,而是使用了ORDER BY子查询:
SELECT *
FROM `table_a`
WHERE table_a.col = 'value'
ORDER BY (
SELECT date
FROM table_b
WHERE id = table_a.id
) ASC
LIMIT 0,20