Максимальный размер запроса SQL Server? В пункте? Есть ли лучший подход

Возможный дубликат:
T-SQL WHERE col IN()< /а>

Каков максимальный размер запроса SQL Server? (количество символов)

Максимальный размер предложения IN? Я думаю, что я видел что-то о том, что Oracle имеет ограничение в 1000 элементов, но вы можете обойти это, объединив 2 IN вместе. Аналогичная проблема в SQL Server?

ОБНОВЛЕНИЕ Итак, что было бы лучшим подходом, если мне нужно взять, скажем, 1000 GUID из другой системы (нереляционной базы данных) и выполнить «СОЕДИНЕНИЕ в коде» с SQL Server? Это отправить список из 1000 GUID в предложение IN?Или есть другой метод, который работает более эффективно?

Я не проверял это, но мне интересно, могу ли я отправить идентификаторы GUID в виде XML-документа. Например

<guids>
    <guid>809674df-1c22-46eb-bf9a-33dc78beb44a</guid>
    <guid>257f537f-9c6b-4f14-a90c-ee613b4287f3</guid>
</guids>

а затем выполните какое-то соединение XQuery JOIN с документом и таблицей. Менее эффективен, чем пункт IN из 1000 пунктов?


person BuddyJoe    schedule 08.12.2009    source источник
comment
Кажется, это дубликат: stackoverflow.com/questions/1069415/t-sql-where-col -в   -  person Yishai    schedule 08.12.2009
comment
Позвольте мне добавить к вопросу, чтобы сделать его более уникальным. см. обновление   -  person BuddyJoe    schedule 09.12.2009
comment
ресурс, который я нашел для обсуждения некоторых идей - sommarskog.se/arrays-in-sql -2005.html#InsertMany   -  person BuddyJoe    schedule 09.12.2009


Ответы (4)


Каждый пакет SQL должен соответствовать пределу размера пакета: 65 536 * Сеть Размер пакета.

Помимо этого, ваш запрос ограничен условиями выполнения. Обычно размер стека иссякает, потому что x IN (a,b,c) есть не что иное, как x=a ИЛИ x=b ИЛИ x=c, что создает дерево выражений, подобное x=a ИЛИ (x=b ИЛИ (x =c)), поэтому он становится очень глубоким с большим количеством OR. SQL 7 достиг бы SO около 10 000 значений в IN, но современные стеки намного глубже ( из-за x64), так что это может быть довольно глубоко.

Обновить

Вы уже нашли статью Эрланда на тему передачи списков/массивов в SQL Server. В SQL 2008 у вас также есть табличные параметры, которые позволяют передавать весь DataTable как один параметр типа таблицы и присоединиться к нему.

XML и XPath — еще одно жизнеспособное решение:

SELECT ...
FROM Table
JOIN (
   SELECT x.value(N'.',N'uniqueidentifier') as guid
   FROM @values.nodes(N'/guids/guid') t(x)) as guids
 ON Table.guid = guids.guid;
person Remus Rusanu    schedule 08.12.2009
comment
размер стека: это ошибка, которую я не мог вспомнить - person gbn; 09.12.2009
comment
@gbn, я считаю, что ошибка связана с переполнением стека, и, следовательно, мы нашли правильный веб-сайт для решения этой проблемы. - person Rudimentary; 27.11.2019

Максимальные значения SQL Server раскрываются http://msdn.microsoft.com/en-us/library/ms143432.aspx (это версия 2008 г.)

SQL-запрос может быть varchar (max), но отображается как ограниченный размером 65 536 * сетевых пакетов, но даже в этом случае вас, скорее всего, сбивают с толку 2100 параметров на запрос. Если SQL решит параметризовать литеральные значения в предложении in, я думаю, что вы сначала достигнете этого предела, но я не проверял это.

Редактировать: протестируйте его, даже при принудительной параметризации он выжил - я провел быстрый тест и выполнил его с 30 000 элементов в предложении In. (SQL сервер 2005)

При 100 000 элементов это заняло некоторое время, а затем упало с:

Сообщение 8623, уровень 16, состояние 1, строка 1 Обработчик запросов исчерпал внутренние ресурсы и не смог создать план запроса. Это редкое событие, ожидаемое только для очень сложных запросов или запросов, которые ссылаются на очень большое количество таблиц или разделов. Пожалуйста, упростите запрос. Если вы считаете, что получили это сообщение по ошибке, обратитесь в службу поддержки клиентов для получения дополнительной информации.

Так что 30к можно, но то, что ты можешь это сделать - не значит, что ты должен :)

Изменить: продолжение из-за дополнительного вопроса.

50k работало, но 60k выпадало, так что где-то там, на моей тестовой установке, кстати.

С точки зрения того, как выполнить это объединение значений без использования большого предложения in, лично я бы создал временную таблицу, вставил значения в эту временную таблицу, проиндексировал ее, а затем использовал в объединении, предоставив ей наилучшие возможности для оптимизировать соединения. (Создание индекса для временной таблицы создаст для нее статистику, которая, как правило, поможет оптимизатору, хотя 1000 GUID точно не сочтут статистику слишком полезной.)

person Andrew    schedule 08.12.2009
comment
смотрите обновление. спасибо за тест +1 - person BuddyJoe; 09.12.2009
comment
К сожалению, эти запросы будут происходить на регулярной основе. Поэтому я не думаю, что индексация временной таблицы возможна. А для максимальных быстрых вставок основная таблица будет индексироваться с помощью int 'addid' (не будет индексироваться по GUID). Этот материал сложнее, чем я думал. - person BuddyJoe; 09.12.2009
comment
Вы рискуете немного преждевременной оптимизацией — вам нужно получить некоторые точные инструментальные данные с точки зрения планов запросов для вашей рабочей нагрузки, поскольку ее будет сложно смоделировать. Как только вы узнаете цифры различных подходов, вы можете сделать выбор, но вставка 1k строк во временную таблицу SQL может быть выполнена исключительно быстро, это действительно зависит от того, как/что это движет. - person Andrew; 09.12.2009
comment
Вам не нужно каждый раз создавать temptable. Если это важная бизнес-логика, просто создайте статическую таблицу с индексированием, массово вставьте идентификаторы и присоединитесь. Индексирование поможет и на короткое время, потому что SQL будет хранить данные, зная, как они будут использоваться. - person Kobor42; 12.02.2017

На пакет 65536 * Размер сетевого пакета, что составляет 4 КБ, поэтому 256 МБ.

Однако IN остановится задолго до этого, но это не точно.

В итоге вы получаете ошибки памяти, но я не могу вспомнить точную ошибку. Огромный IN все равно будет неэффективен.

Изменить: Ремус напомнил мне: ошибка связана с «размером стека».

person gbn    schedule 08.12.2009

Можете ли вы загрузить идентификаторы GUID в рабочую таблицу, а затем выполнить

... WHERE var IN SELECT guid FROM #scratchtable
person DaveE    schedule 08.12.2009
comment
Если вы предполагаете, что у вас будут эти запросы каждую секунду или две. Интересно, как выдержит скретч-стол. - person BuddyJoe; 09.12.2009
comment
Мы широко используем эту технику в нашем приложении, и, похоже, она работает хорошо. База данных Tempdb должна быть большой, и мы делаем некоторые настройки при установке — я не знаю подробностей этого. Tempdb действительно занят. - person DaveE; 09.12.2009