Я вижу несколько проблем здесь и пытаюсь сделать шаг назад:
Прежде всего, как уже упоминалось, способ передачи параметров является неоптимальным. IN
не предназначен для передачи таких длинных списков параметров. В этих случаях IN использует огромное количество ресурсов, что, скорее всего, приведет к вашей обнаруженной проблеме.
Техническим решением для этого будет создание временной таблицы или использование и присоединение к пользовательской таблице. Как указано в комментариях, это не одно и то же, и FROM (VALUES ()) может работать в некоторых случаях, но не в других.
С временной таблицей это будет выглядеть как
string query = $@" CREATE TABLE @ids (id INT);
INSERT INTO @ids VALUES {string.Join(",", ids.Select(id => $"({id})"))}
SELECT u.*
FROM @ids Ids
JOIN dbo.Users u ON u.Id = Ids.Id
Можно также использовать FROM (VALUES(...))
, но, как упоминал мой комментатор ниже, это не гарантируется для работы. Это будет выглядеть примерно так:
string query = $@" SELECT u.*
FROM (
VALUES {string.Join(",", ids.Select(id => $"({id})"))}
) AS Ids(Id)
JOIN dbo.Users u ON u.Id = Ids.Id";
Второе, что я заметил, это то, что этот запрос всегда загружает полный пользовательский объект. Я предполагаю, что вызывающий метод затем выполняет некоторую операцию с теми пользователями, которые являются только подмножеством пользовательских данных? В этом случае было бы чище просто вернуть данные, необходимые на этом конкретном этапе приложения, и сделать ограниченный выбор. Это сокращает объем данных, которые необходимо прочитать с диска и резко передать в приложение, и, следовательно, может значительно повысить производительность