使用 JOIN 而不是 NOT IN 优化 SQL 查询

Posted

技术标签:

【中文标题】使用 JOIN 而不是 NOT IN 优化 SQL 查询【英文标题】:Optimizing SQL query using JOIN instead of NOT IN 【发布时间】:2017-05-31 16:07:27 【问题描述】:

我有一个要优化的 sql 查询。我不是数据库的设计者,所以我无法更改结构、索引或存储过程。

我有一个包含发票(称为 faktura)的表,每张发票都有一个唯一的发票 ID。如果我们必须取消发票,则会在同一张表中创建第二张发票,但其中的字段(“modpartfakturaid”)引用原始发票 ID。

faktura 表示例:

invoice 1: Id=152549, modpartfakturaid=null

invoice 2: Id=152592, modpartfakturaid=152549

我们还有一个名为“BHLFORLINIE”的表,其中包含为客户提供的服务。部分服务已开具发票并与发票 (FAKTURA) 表中的记录相匹配。

我想做的是获取所有服务的列表,这些服务要么没有发票,要么没有已取消的发票。

我现在正在做的是:

`SELECT
    dbo.BHLFORLINIE.LeveringsDato AS treatmentDate,
    dbo.PatientView.Navn AS patientName,
    dbo.PatientView.CPRNR AS patientCPR
FROM
    dbo.BHLFORLINIE
INNER JOIN dbo.BHLFORLOEB 
    ON dbo.BHLFORLOEB.BhlForloebID = dbo.BHLFORLINIE.BhlForloebID
INNER JOIN dbo.PatientView 
    ON dbo.PatientView.PersonID = dbo.BHLFORLOEB.PersonID
INNER JOIN dbo.HENVISNING 
    ON dbo.HENVISNING.BhlForloebID = dbo.BHLFORLOEB.BhlForloebID
LEFT JOIN dbo.FAKTURA 
    ON dbo.BHLFORLINIE.FakturaId = FAKTURA.FakturaId
WHERE
    (dbo.BHLFORLINIE.LeveringsDato >= '2017-01-01' OR dbo.BHLFORLINIE.FakturaId IS NULL) AND
    dbo.BHLFORLINIE.ProduktNr IN (110,111,112,113,8050,4001,4002,4003,4004,4005,4006,4007,4008,4009,6001,6002,6003,6004,6005,6006,6007,6008,7001,7002,7003,7004,7005,7006,7007,7008) AND
    ((dbo.FAKTURA.FakturaType = 0 AND 
      dbo.FAKTURA.FakturaID NOT IN (
      SELECT FAKTURA.ModpartFakturaID FROM FAKTURA WHERE FAKTURA.ModpartFakturaID IS NOT NULL
      )) OR 
    dbo.FAKTURA.FakturaType IS NULL) 
 GROUP BY
    dbo.PatientView.CPRNR,
    dbo.PatientView.Navn,
    dbo.BHLFORLINIE.LeveringsDato`

有更聪明的方法吗?现在,由于“不在”子查询中,添加的查询执行速度慢了三倍。

非常感谢任何帮助!

彼得

【问题讨论】:

【参考方案1】:

您可以使用外连接并检查空值来查找不匹配项

SELECT customer.name, invoice.id 
FROM invoices i
INNER JOIN customer ON i.customerId = customer.customerId 
LEFT OUTER JOIN invoices i2 ON i.invoiceId = i2.cancelInvoiceId
WHERE i2.invoiceId IS NULL

【讨论】:

感谢您的快速回复!我想我可能举了一个非常糟糕的例子——对不起!我修改了我的原始问题以显示我正在执行的查询。发票表不是我要加入的表。

以上是关于使用 JOIN 而不是 NOT IN 优化 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

我啥时候应该使用 CROSS APPLY 而不是 INNER JOIN?

在 PHP While 循环中使用 MySQL JOIN 而不是查询

何时更喜欢用 SelectMany() 表示的连接而不是用 Linq 中的 join 关键字表示的连接

GraphQL 如何做一个 JOIN 请求而不是许多顺序请求?

Spring JPA/Hibernate Repository findAll 在 Kotlin 中默认执行 N+1 个请求而不是 JOIN

如何使 OUTER JOIN 返回零而不是 NULL