我需要编写一个查询来检索一个大的id列表.
我们支持许多后端(MySQL,Firebird,SQLServer,Oracle,PostgreSQL ......)所以我需要编写一个标准的SQL.
id集的大小可能很大,查询将以编程方式生成.那么,最好的方法是什么?
SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Run Code Online (Sandbox Code Playgroud)
我的问题是.如果n很大会怎么样?还有,性能呢?
SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn
Run Code Online (Sandbox Code Playgroud)
我认为这种方法没有n限制,但如果n非常大,那么性能呢?
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在性能方面非常糟糕.它在每个循环中发送一个查询,并用小查询对数据库进行锤击.它还阻止它使用"值是给定列表中的值之一"的任何优化
Ed *_*ess 24
另一种方法可能是使用另一个表来包含id值.然后,可以将另一个表内部连接到TABLE上以约束返回的行.这将具有以下主要优点:您不需要动态SQL(在最好的时候会出现问题),并且您将不会拥有无限长的IN子句.
您将截断此另一个表,插入大量行,然后创建索引以帮助加入性能.它还可以让您从数据检索中分离这些行的累积,或许可以为您提供更多选项来调整性能.
更新:虽然您可以使用临时表,但我并不是要暗示您必须或甚至应该使用临时表.用于临时数据的永久表是一种常见的解决方案,具有超出此处所述的优点.
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)
并且性能大幅提升.
第一种选择绝对是最好的选择.
SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Run Code Online (Sandbox Code Playgroud)
但是考虑到id的列表非常庞大,比如数百万,你应该考虑下面的块大小:
你为什么要分成几块?
你永远不会得到内存溢出异常,这在像你这样的场景中很常见.您将获得优化的数据库调用次数,从而提高性能.
对我来说,它总是像魅力一样.希望它对我的同事们也有用:)
在具有 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)
使用连接。