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

我需要写一个查询来检索一个大的ID列表。

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

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

1)用IN写一个查询

SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn) 

我的问题在这里。 如果n很大,会发生什么? 另外,性能呢?

2)使用OR编写查询

 SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn 

我认为这个方法没有n限制,但是如果n很大,性能如何呢?

3)编写一个编程解决scheme:

  foreach (id in myIdList) { item = GetItemByQuery("SELECT * FROM TABLE WHERE ID = " + id); myObjectList.Add(item); } 

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

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

选项1是唯一的好的解决scheme。

为什么?

  • 选项2也是一样的,但你重复列名很多次; 此外,SQL引擎不会立即知道您要检查值是否是固定列表中的值之一。 但是,一个好的SQL引擎可以优化它与IN相同的性能。 仍然有可读性问题,但…

  • 选项3在性能方面非常糟糕。 它每循环发送一个查询,并用小的查询敲击数据库。 它也阻止它使用任何优化“价值是给定列表中的一个”

另一种方法可能是使用另一个表来包含id值。 这个其他表然后可以在您的TABLE内部join,以约束返回的行。 这将有一个主要的优点,就是你不需要dynamicSQL(在最好的时候有问题),而且你不会有一个无限长的IN子句。

你会截断这个其他表,插入大量的行,然后可能创build一个索引来帮助连接性能。 它也可以让你从数据检索中分离出这些行的积累,也许给你更多的select来调整性能。

更新 :虽然你可以使用一个临时表,但我不是故意暗示你必须甚至应该。 用于临时数据的永久表是常见的解决scheme,具有超出此处描述的优点。

Guinessbuild议的东西真的是一个性能的助推器,我有这样的查询

 select * from table where id in (id1,id2.........long list) 

我做了什么 :

  DECLARE @temp table( ID int ) insert into @temp select * from dbo.fnSplitter('#idlist#') 

然后内部join主表的温度:

 select * from table inner join temp on temp.id = table.id 

性能大幅提升。

在大多数数据库系统中, IN (val1, val2, …)和一系列OR被优化为相同的计划。

第三种方法是将值列表导入到一个临时表中,并join到大多数系统中,如果有很多值的话。

你可能想阅读这篇文章:

  • 在MySQL中传递参数:IN列表与临时表

样本3将是他们之中performance最差的一个,因为你没有明显的原因无数次地敲击数据库。

将数据加载到临时表中,然后join,将是迄今为止最快的。 之后,IN应该比OR组略快。

第一个选项绝对是最好的select。

 SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn) 

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

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

你为什么要分成几块?

你将永远不会得到内存溢出exception,这在你的场景中是非常普遍的。 您将优化数据库调用的数量,从而获得更好的性能。

它一直为我的魅力。 希望它可以为我的开发人员以及:)

我认为你的意思是SqlServer,但在Oracle上,你有一个硬限制你可以指定多lessIN元素:1000。