SQL,试图摆脱大 IN 子句

Posted

技术标签:

【中文标题】SQL,试图摆脱大 IN 子句【英文标题】:SQL, trying to get rid of large IN cluase 【发布时间】:2015-11-23 03:43:10 【问题描述】:

我有一张桌子,

Contacts: Contact_ID (int) ContactName (nvarchar)

我得到了一个可供选择的联系人 ID 列表。通常,我会这样做

SELECT *
FROM Contacts
WHERE IN (List of contact ID)

问题是,联系人 ID 列表可能会变得非常大,例如 50k 或更多。

所以我的问题是,有没有一种方法可以处理大量的联系人 ID 而无需使用 IN 子句?

编辑:我正在使用 Microsoft sql 服务器。查询和联系人 ID 在运行时构建并传递给 sqlCommand 类 (c#) 以执行。

【问题讨论】:

在两个表之间使用连接并允许 INNER 连接消除记录...使用相关子查询和 'exists' 子句(或类似的,取决于 RDBMS)(Exists 是 一般最快的其次是内部连接,其次是IN)那么什么RDBMS?表格中的联系人 ID 列表是否在某处? (不确定“给定联系人列表”是什么意思将“列表”插入临时表并使用存在或内部连接......但这有开销......你想要实现什么?只是提高了可读性? 您使用的是哪个 DBMS?每个优化器的行为都不同 不确定您使用的是哪个 DBMS,但大多数都允许您将这些 ID 放入临时表并加入临时表。那可能会更快。 SQLServer 自动将大型 IN 子句(>50 项左右)转换为 TempTable + EXISTS。更改对性能没有好处。 @xQbert 好像我的问题有点含糊,抱歉。我应该澄清查询是在运行时构建的,联系人 ID 列表也是如此。当我试图用一个大的 in 子句运行这个查询时,它 sql server 给了我一个“内部资源用完”的错误。 【参考方案1】:

我会创建一个包含单列和聚集主键的表类型。

CREATE TYPE dbo.ContactId AS TABLE
(
    ContactId INT NOT NULL PRIMARY KEY 
);

使用表值参数将值传递到查询中。

将您的查询更改为

SELECT *
FROM Contacts
WHERE contactID  IN (SELECT y.contactID FROM @yourtablevaluedparameter y)
OPTION (RECOMPILE)

OPTION (RECOMPILE) 用于获取考虑的行数,因为 50K 的最佳计划可能与 1 的不同。

You can find some example C# code for populating a TVP here

【讨论】:

创建另一个表可能是要走的路。我现在正在尝试这个解决方案。会让你知道!谢谢!【参考方案2】:

如果你想要性能,我会使用 EXISTS 子句。

SELECT c.Contact_ID, c.ContactName
FROM Contacts c
WHERE EXISTS (List of contact ID)

【讨论】:

不清楚 OP 应该如何将其与“联系人 ID 列表”一起使用。 INEXISTS 在 SQL Server 中给出相同的计划(不像 NOT INNOT EXISTS 抱歉,当我回答他时,他没有提供太多关于他的问题的信息。【参考方案3】:

创建一个临时表并以行的形式填充您的联系人 ID。 在您的表和临时表之间进行内部连接,如下所示。

SELECT c.*
FROM Contacts c
join #temptable t
on c.id=t.id

如果您在临时表的 Join 列上引入索引,那么您的查询会更快。

【讨论】:

以上是关于SQL,试图摆脱大 IN 子句的主要内容,如果未能解决你的问题,请参考以下文章

linqpad - 大 NOT IN 子句超出限制 - 还有其他方式吗? - Linq to SQL

Apache Camel 2.18中的IN子句

MySql IN 子句,试图匹配元组的 IN 列表

IN子句中的Spark sql限制

我们应该在检索数据时避免 DB2 SQL 中的 IN 子句吗?

在本机 sql 查询中使用 IN 子句