SQL WHERE ID IN(id1,id2,...,idn)

Dan*_*lba 151 sql select

我需要编写一个查询来检索一个大的id列表.

我们支持许多后端(MySQL,Firebird,SQLServer,Oracle,PostgreSQL ......)所以我需要编写一个标准的SQL.

id集的大小可能很大,查询将以编程方式生成.那么,最好的方法是什么?

1)使用IN编写查询

SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Run Code Online (Sandbox Code Playgroud)

我的问题是.如果n很大会怎么样?还有,性能呢?

2)使用OR编写查询

SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn
Run Code Online (Sandbox Code Playgroud)

我认为这种方法没有n限制,但如果n非常大,那么性能呢?

3)编写程序化解决方案:

  foreach (var id in myIdList)
  {
      var item = GetItemByQuery("SELECT * FROM TABLE WHERE ID = " + id);
      myObjectList.Add(item);
  }
Run Code Online (Sandbox Code Playgroud)

当通过网络查询数据库服务器时,我们遇到了这种方法的一些问题.通常最好做一个检索所有结果的查询,更好的是那么多小的查询.也许我错了.

什么是这个问题的正确解决方案?

Thi*_*ter 98

选项1是唯一的好解决方案.

为什么?

  • 选项2执行相同但您重复列名称很多次; 此外,SQL引擎不会立即知道您要检查该值是否是固定列表中的值之一.但是,一个好的SQL引擎可以优化它以获得与之相同的性能IN.尽管如此,仍然存在可读性问题......

  • 选项3在性能方面非常糟糕.它在每个循环中发送一个查询,并用小查询对数据库进行锤击.它还阻止它使用"值是给定列表中的值之一"的任何优化

  • 我同意,但是请注意,在许多RDMS中,in列表受到限制,因此您需要我们使用@Ed Guiness的解决方案,但此处的临时表在RDBMS之间确实有所不同。(有效地解决了复杂的问题,您不能只使用纯标准的SQL) (2认同)

Ed *_*ess 24

另一种方法可能是使用另一个表来包含id值.然后,可以将另一个表内部连接到TABLE上以约束返回的行.这将具有以下主要优点:您不需要动态SQL(在最好的时候会出现问题),并且您将不会拥有无限长的IN子句.

您将截断此另一个表,插入大量行,然后创建索引以帮助加入性能.它还可以让您从数据检索中分离这些行的累积,或许可以为您提供更多选项来调整性能.

更新:虽然您可以使用临时表,但我并不是要暗示您必须或甚至应该使用临时表.用于临时数据的永久表是一种常见的解决方案,具有超出此处所述的优点.

  • @raam86:ID 列表可能是在另一个表上使用 `select` 语句获得的。该列表作为您正在“内部联接”的另一个表传递。 (2认同)

Rit*_*itu 14

Ed Guiness建议的确是一个性能助推器,我有这样的查询

select * from table where id in (id1,id2.........long list)
Run Code Online (Sandbox Code Playgroud)

我做了什么 :

DECLARE @temp table(
            ID  int
            )
insert into @temp 
select * from dbo.fnSplitter('#idlist#')
Run Code Online (Sandbox Code Playgroud)

然后内部用主表连接temp:

select * from table inner join temp on temp.id = table.id
Run Code Online (Sandbox Code Playgroud)

并且性能大幅提升.

  • 嗨,fnSplitter 是 MSSQL 的函数吗?因为我找不到它。 (2认同)

Ada*_*mar 8

第一种选择绝对是最好的选择.

SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Run Code Online (Sandbox Code Playgroud)

但是考虑到id的列表非常庞大,比如数百万,你应该考虑下面的块大小:

  • 将你的ID列表分成固定数量的块,比如说100
  • 块大小应根据服务器的内存大小决定
  • 假设您有10000个Ids,您将拥有10000/100 = 100个块
  • 一次处理一个块,导致100个数据库调用select

你为什么要分成几块?

你永远不会得到内存溢出异常,这在像你这样的场景中很常见.您将获得优化的数据库调用次数,从而提高性能.

对我来说,它总是像魅力一样.希望它对我的同事们也有用:)


Jak*_*keJ 7

在具有 5 亿条记录的 Azure SQL 表上执行 SELECT * FROM MyTable where id in () 命令导致等待时间超过 7 分钟!

这样做反而会立即返回结果:

select b.id, a.* from MyTable a
join (values (250000), (2500001), (2600000)) as b(id)
ON a.id = b.id
Run Code Online (Sandbox Code Playgroud)

使用连接。