我试图在下面的(制作)示例中说明问题。本质上,我想根据辅助表中的内容过滤主表中的记录。当我使用子查询尝试这个时,我们的应用程序性能受到了很大的打击(有些查询慢了近10倍)。
在此示例中,我想返回客户的所有案例说明,除非在详细信息表中引用了产品1111和2222:
select cn.id, cn.summary from case_notes cn
where customer_id = 2
and exists (
select 1 from case_note_details cnd
where cnd.case_note_id = cn.id
and cnd.product_id not in (1111,2222)
)
我也试过使用连接:
select distinct cn.id, cn.summary from case_notes cn
join case_note_details cnd
on cnd.case_note_id = cn.id
and cnd.product_id not in (1111,2222)
where customer_id = 2
在这两种情况下,执行计划都会显示两个聚簇索引扫描。有关其他方法或调整以改善性能的建议吗?
架构:
CREATE TABLE case_notes
(
id int primary key,
employee_id int,
customer_id int,
order_id int,
summary varchar(50)
);
CREATE TABLE case_note_details
(
id int primary key,
case_note_id int,
product_id int,
detail varchar(1024)
);
示例数据:
INSERT INTO case_notes
(id, employee_id, customer_id, order_id, summary)
VALUES
(1, 1, 2, 1000, 'complaint1'),
(2, 1, 2, 1001, 'complaint2'),
(3, 1, 2, 1002, 'complaint3'),
(4, 1, 2, 1003, 'complaint4');
INSERT INTO case_note_details
(id, case_note_id, product_id, detail)
VALUES
(1, 1, 1111, 'Note 1, order 1000, complaint about product 1111'),
(2, 1, 2222, 'Note 1, order 1000, complaint about product 2222'),
(3, 2, 1111, 'Note 2, order 1001, complaint about product 1111'),
(4, 2, 2222, 'Note 2, order 1001, complaint about product 2222'),
(5, 3, 3333, 'Note 3, order 1002, complaint about product 3333'),
(6, 3, 4444, 'Note 3, order 1002, complaint about product 4444'),
(7, 4, 5555, 'Note 4, order 1003, complaint about product 5555'),
(8, 4, 6666, 'Note 4, order 1003, complaint about product 6666');
答案 0 :(得分:2)
您有一个聚簇索引扫描,因为您没有通过其id但通过非索引列访问您的case_note_details表。
我建议在case_note_id,product_id上的case-note_details表中添加一个索引。
如果您始终通过case_note_id访问case_note_details,则可能还会将主键重构为case_note_id,detail_id。不需要独立的id作为依赖记录的主键。这将允许您重新使用详细主键索引来连接头表。
编辑:像在Manuel Rocha建议的那样,在customer_id上添加一个索引到case_notes表。
答案 1 :(得分:1)
使用"存在"我总是用" TOP"来限制结果。如下:
select cn.id
,cn.summary
from case_notes as cn
where customer_id = 2
and exists (
select TOP 1 1
from case_note_details as cnd
where cnd.case_note_id = cn.id
and cnd.product_id not in (1111,2222)
)
答案 2 :(得分:1)
在表格 case_notes 中为 customer_id 创建索引,在表格 case_note_details 上为 case_note_id 和创建索引case_note_id 强>
然后尝试执行两个查询。现在应该有更好的表现。
也可以尝试此查询
select
cn.id,
cn.summary
from
case_notes cn
where
cn.customer_id = 2 and
cn.id in
(
select
distinct cnd.case_note_id
from
case_note_details cnd
where
cnd.product_id not in (1111,2222)
)
答案 3 :(得分:0)
您是否尝试过“in”而不是“exists”。这有时会有所不同:
select cn.id, cn.summary from case_notes cn
where customer_id = 2
and cn.id in (
select cnd.case_note_id from case_note_details cnd
where cnd.product_id not in (1111,2222)
)
当然,检查索引。