如何進行 SQL 查詢以選擇至少沒有一個子元素的記錄?
我有 3 個表:文章(約 4 萬行)、日歷(約 45 萬行)和calendar_cost(~500K 行)。
有必要選擇文章表的此類條目:
- 日歷中沒有條目表
- 如果日歷表中有條目,則所有條目都不應在calendar_cost表中有任何條目。
create table article (
id int PRIMARY KEY,
name varchar
);
create table calendar (
id int PRIMARY KEY,
article_id int REFERENCES article (id) ON DELETE CASCADE,
number varchar
);
create table calendar_cost (
id int PRIMARY KEY,
calendar_id int REFERENCES calendar (id) ON DELETE CASCADE,
cost_value numeric
);
insert into article (id, name) values
(1, 'Article 1'),
(2, 'Article 2'),
(3, 'Article 3');
insert into calendar (id, article_id, number) values
(101, 1, 'Point 1-1'),
(102, 1, 'Point 1-2'),
(103, 2, 'Point 2');
insert into calendar_cost (id, calendar_id, cost_value) values
(400, 101, 100.123),
(401, 101, 400.567);
因此,“第 2 條”(條件 2)和“第 3 條”(條件 1)將適合我們。
我的 SQL 查詢很慢(第二個條件部分),我怎樣才能做到最好?沒有“聯合所有”運算子可以嗎?
-- First condition
select a.id from article a
left join calendar c on a.id = c.article_id
where c.id is null
union all
-- Second condition
select a.id from article a
where id not in(
select aa.id from article aa
join calendar c on aa.id = c.article_id
join calendar_cost cost on c.id = cost.calendar_id
where aa.id = a.id limit 1
)
uj5u.com熱心網友回復:
無需拆分條件:您需要檢查的唯一條件是沒有任何calendar_cost行,如果沒有行就是這種情況calendar。
訣竅是使用外部聯接,它仍然回傳父表,但null在沒有聯接時具有所有值。此外,count()不計算null值,因此只需要計數calendar_cost為零即可。
select a.id
from article a
left join calendar c on c.article_id = a.id
left join calendar_cost cost on cost.calendar_id = c.id
group by a.id
having count(cost.calendar_id) = 0
觀看現場演示。
如果列上有索引id(通常情況下),考慮到較小的表大小,此查詢將執行得相當好。
uj5u.com熱心網友回復:
您的第二個條件應該像您的第一個條件一樣開始:找到所有沒有日歷成本的日歷條目,然后才將其加入文章。
select a.id
from article a
Inner Join (
Select article_id
From calendar c left join calendar_cost cc
On c.id=cc.calendar_id
Where cc.calendar_id is null
) cnone
On a.id = cnone.article_id
這種方法是基于這樣的想法,即沒有 calendar_cost 的日歷條目與所有日歷條目相比相對較少。
uj5u.com熱心網友回復:
您的查詢無效,因為 IN 子句不支持 LIMIT
在 article_id 和 calender_id 上添加一些索引
將有助于表現
正如您在查詢計劃中看到的
create table article (
id int PRIMARY KEY,
name varchar(100)
);
create table calendar (
id int PRIMARY KEY,
article_id int REFERENCES article (id) ON DELETE CASCADE,
number varchar(100)
,index(article_id)
);
create table calendar_cost (
id int PRIMARY KEY,
calendar_id int REFERENCES calendar (id) ON DELETE CASCADE,
cost_value numeric
,INDEX(calendar_id)
);
insert into article (id, name) values
(1, 'Article 1'),
(2, 'Article 2'),
(3, 'Article 3');
insert into calendar (id, article_id, number) values
(101, 1, 'Point 1-1'),
(102, 1, 'Point 1-2'),
(103, 2, 'Point 2');
insert into calendar_cost (id, calendar_id, cost_value) values
(400, 101, 100.123),
(401, 101, 400.567);
Records: 3 Duplicates: 0 Warnings: 0
Records: 3 Duplicates: 0 Warnings: 0
Records: 2 Duplicates: 0 Warnings: 2
select a.id from article a
left join calendar c on a.id = c.article_id
where c.id is null
| ID |
|---|
| 3 |
-- First condition
EXPLAIN
select a.id from article a
left join calendar c on a.id = c.article_id
where c.id is null
union all
-- Second condition
select a.id from article a
JOIN (
select aa.id from article aa
join calendar c on aa.id = c.article_id
join calendar_cost cost on c.id = cost.calendar_id
LIMIT 1
) t1 ON t1.id <> a.id
| ID | 選擇型別 | 桌子 | 磁區 | 型別 | 可能的鍵 | 鑰匙 | key_len | 參考 | 行 | 過濾 | 額外的 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 基本的 | 一個 | 無效的 | 指數 | 無效的 | 基本的 | 4 | 無效的 | 3 | 100.00 | 使用索引 |
| 1 | 基本的 | C | 無效的 | 參考 | article_id | article_id | 5 | 小提琴.a.id | 3 | 33.33 | 使用哪里;不存在; 使用索引 |
| 2 | 聯盟 | <派生3> | 無效的 | 系統 | 無效的 | 無效的 | 無效的 | 無效的 | 1 | 100.00 | 無效的 |
| 2 | 聯盟 | 一個 | 無效的 | 指數 | 無效的 | 基本的 | 4 | 無效的 | 3 | 66.67 | 使用哪里;使用索引 |
| 3 | 衍生的 | 成本 | 無效的 | 指數 | 日歷ID | 日歷ID | 5 | 無效的 | 2 | 100.00 | 使用哪里;使用索引 |
| 3 | 衍生的 | C | 無效的 | eq_ref | PRIMARY,article_id | 基本的 | 4 | fiddle.cost.calendar_id | 1 | 100.00 | 使用哪里 |
| 3 | 衍生的 | 啊 | 無效的 | eq_ref | 基本的 | 基本的 | 4 | fiddle.c.article_id | 1 | 100.00 | 使用索引 |
小提琴
uj5u.com熱心網友回復:
使用存在的組合嘗試以下操作條件
通常,使用支持索引,這比簡單地連接表更有效,因為它提供了一個短路,一旦找到匹配項就可以退出,而連接通常會在所有行連接后進行過濾。
select a.id
from article a
where not exists (
select * from calendar c
where c.article_id = a.id
)
or (exists (
select * from calendar c
where c.article_id = a.id
)
and not exists (
select * from calendar_cost cc
where cc.calendar_id in (select id from calendar c where c.article_id = a.id)
)
);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/532078.html
