简体   繁体   English

对于许多值,SQL Server IN子句的等效速度更快

[英]Faster equivalent of SQL Server IN clause for many values

I'm using OrmLite .NET with SQL Server 12.0. 我在SQL Server 12.0中使用OrmLite .NET。 I want to select entities where a certain integer column (not the primary key) has one of many values, which I have in an array. 我想选择某些整数列(不是主键)具有数组中包含的多个值之一的实体。 An OrmLite expression like this: 像这样的OrmLite表达式:

q => query.Where(r => myIntegers.Contains(r.TheColumn))

gets translated to 被翻译成

WHERE "TheColumn" IN (1, 2, 3, ...) -- my integers

This works fine with ~100, but times out with 1000. How do I achieve the same effect with a larger list? 〜100可以正常工作,但1000可以超时。如何使用更大的列表达到相同的效果? Can I pass an array to SQL Server somehow or a table parameter? 是否可以将数组或表参数传递给SQL Server?

Similar to what @JoeTaras commented, you can put the acceptable values into a subquery, something like; 类似于@JoeTaras评论的内容,您可以将可接受的值放入子查询中,例如:

SELECT TheColumn from TheTable T
INNER JOIN (SELECT * from (VALUES(1),(2),(3),(4)) as V1(value)) V
ON T.TheColumn = V.value

In OrmLite you may build raw SQL query you need (for example, from @Sam cd answer) and pass it to db.Select method: 在OrmLite中,您可以构建所需的原始SQL查询(例如,通过@Sam cd答案)并将其传递给db.Select方法:

string joinedIds = string.Join("),(", new List<int> {1, 2, 9});

string command =
    $"SELECT * from Employee AS E INNER JOIN (SELECT * from (VALUES( {joinedIds} )) as TV(value)) V ON E.Id = V.value";

List<Employee> employers = db.Select<Employee>(command);

I ended up using a temporary table for this, ie: 我最终为此使用了一个临时表,即:

CREATE TABLE #ParamTempTable (Id BIGINT NOT NULL PRIMARY KEY);

INSERT INTO #ParamTempTable (Id) VALUES ((1), (2), (3));

SELECT *
FROM MyTable
WHERE Id IN (SELECT * FROM #ParamTempTable);

DROP TABLE #ParamTempTable;

I do this only when I have > 1000 values, otherwise I just use SQL IN (1, 2, 3) . 仅当我具有> 1000个值时才执行此操作,否则我只使用SQL IN (1, 2, 3)

To implement this on OrmLite I had to subclass SqlServerExpression<T> and override VisitStaticArrayMethodCall and VisitEnumerableMethodCall to change how it handled Contains expressions. 为了在OrmLite上实现此功能,我必须继承SqlServerExpression<T>子类,并重写VisitStaticArrayMethodCallVisitEnumerableMethodCall来更改其处理Contains表达式的方式。 This class stores the commands to create and drop the temp tables separately and I have to run separate a SqlCommand for each of those. 此类存储用于分别创建和删除临时表的命令,而我必须分别为它们运行一个SqlCommand ( CREATE TABLE doesn't work in SqlCommand.ExecuteReader , unfortunately.) So this ended up being quite complicated, but it does work and is transparent to the caller. (不幸的是, CREATE TABLESqlCommand.ExecuteReader不起作用。)因此,这最终变得相当复杂,但它确实有效并且对调用者是透明的。 An added benefit is that I could eliminate duplicate parameters, so eg for o => ids.Contains(o.FromId) || ids.Contains(o.ToId) 另一个好处是我可以消除重复的参数,例如对于o => ids.Contains(o.FromId) || ids.Contains(o.ToId) o => ids.Contains(o.FromId) || ids.Contains(o.ToId) the list ids gets sent to SQL server only once. o => ids.Contains(o.FromId) || ids.Contains(o.ToId)列表ids仅发送到SQL Server一次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM