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

时间:2011-04-27 11:40:08

标签: sql select

我需要编写一个查询来检索一大堆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)编写程序化解决方案:

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

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

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

9 个答案:

答案 0 :(得分:86)

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

为什么?

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

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

答案 1 :(得分:23)

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

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

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

答案 2 :(得分:10)

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

select * from table where id in (id1,id2.........long list)
我做了什么:

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

然后内部用主表加入了temp:

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

性能大幅提升。

答案 3 :(得分:7)

第一个选项绝对是最佳选择。

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

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

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

为什么要分成几块?

  

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

对我而言,它总是像魅力一样。希望它对我的同事们也有用:)

答案 4 :(得分:3)

在大多数数据库系统中,IN (val1, val2, …)和一系列OR针对同一计划进行了优化。

第三种方法是将值列表导入临时表并加入,如果有大量值,则在大多数系统中更有效。

您可能想阅读这篇文章:

答案 5 :(得分:3)

样本3将是表现最差的,因为你没有明显的理由无数次地使用数据库。

将数据加载到临时表中,然后加入其中,这是迄今为止最快的。之后,IN应该比OR组稍快一些。

答案 6 :(得分:3)

在具有5亿条记录的Azure SQL表上执行SELECT * FROM MyTable,其中id in()命令导致等待时间> 1。 7分钟!

执行此操作会立即返回结果:

select b.id, a.* from MyTable a
join (values (250000), (2500001), (2600000)) as b(id)
ON a.id = b.id

使用联接。

答案 7 :(得分:2)

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

答案 8 :(得分:0)

尝试一下

SELECT Position_ID , Position_Name
FROM 
position
WHERE Position_ID IN (6 ,7 ,8)
ORDER BY Position_Name