我需要帮助才能在一个LEFT JOIN
的SQL查询中选择正确的索引。
我有两个表(对象和月度报告):
CREATE TABLE some_objects (
id int(11) NOT NULL AUTO_INCREMENT,
...,
PRIMARY KEY (id),
);
CREATE TABLE month_reports (
id int(11) NOT NULL AUTO_INCREMENT,
some_object_id int(11) DEFAULT NULL,
month int(11) NOT NULL,
year int(11) NOT NULL,
...,
PRIMARY KEY (id),
INDEX IDX_123 (month, year),
INDEX IDX_456 (some_object_id),
INDEX IDX_789 (some_object_id, month, year),
CONSTRAINT FK_123 FOREIGN KEY (some_object_id)
REFERENCES some_objects (id) ON DELETE RESTRICT ON UPDATE RESTRICT
)
我需要在特定月份选择所有带报告的对象,或者不选择它们。我试过这个问题:
SELECT * FROM some_objects so
LEFT JOIN month_reports mr ON mr.some_object_id = so.id
WHERE
mr.month = :month
AND mr.year = :year
OR mr.id IS NULL
EXPLAIN
结果:
id select_type table type possible_keys
1 SIMPLE so ALL
1 SIMPLE mr ALL IDX_456,IDX_789
EXPLAIN
结果没有OR mr.id IS NULL
:
id select_type table type possible_keys key ref
1 SIMPLE mr ref IDX_123,IDX_456,IDX_789 IDX_123 const,const
1 SIMPLE so eq_ref PRIMARY
但如果没有OR mr.id IS NULL
,我就不会在没有报告的情况下获得对象!
我应该添加哪个其他索引?我需要更改查询吗?
P.S。抱歉我的英文。
UPD。 ANALYZE TABLE
返回"状态正常"。 EXPLAIN
结果为FORCE INDEX
(10个对象,只有一个有报告):
id select_type table type possible_keys key rows
1 SIMPLE so ALL 10
1 SIMPLE mr ref IDX_789 IDX_789 1
答案 0 :(得分:0)
好吧,我没有得到我需要的东西。我会考虑如何以另一种方式解决我的问题。
不幸的是,我无法在我的框架中使用FORCE INDEX
。但即使他们都没有报告,我也需要获得所有对象。
我只想优化我的SQL查询。在单个查询中执行此操作是不成功的尝试:)
答案 1 :(得分:0)
这是可能做你想做的重新制定:
SELECT so.*
FROM some_objects so
LEFT JOIN month_reports mr
ON mr.some_object_id = so.id
AND ( mr.month = :month AND mr.year = :year )
请注意,由于IS NULL
的工作方式,它可以避免处理LEFT
。但是,它会将WHERE
移动到ON
。
使用UNION
代替OR
进行以下重新填充也可能有效(假设框架允许您这样做):
( SELECT so.*
FROM some_objects so
JOIN month_reports mr ON mr.some_object_id = so.id
WHERE mr.month = :month
AND mr.year = :year
)
UNION
( SELECT so.*
FROM some_objects so
LEFT JOIN month_reports mr ON mr.some_object_id = so.id
WHERE mr.id IS NULL
)