Длинный запрос предотвращает вставки - PullRequest
1 голос
/ 14 февраля 2009

У меня есть запрос, который выполняется каждую ночь в таблице с кучей записей (200 000+). Это приложение просто перебирает результаты (используя DbDataReader в приложении C #, если это уместно) и обрабатывает каждый из них. Обработка выполняется за пределами базы данных в целом. В то время, когда приложение перебирает результаты, я не могу вставить какие-либо записи в таблицу, к которой я обращаюсь. Операторы вставки просто зависают и в конечном итоге время ожидания. Вставки сделаны в совершенно разных приложениях.

Блокирует ли SQL Server таблицу во время выполнения запроса? Это похоже на чрезмерно агрессивную политику блокировки. Я мог понять, как может возникнуть конфликт между запросом и вновь вставленными записями, но я был бы в порядке, если бы записи, вставленные после начала запроса, просто не были включены в результаты.

Есть ли способы избежать этого?

Обновление:
THE WITH (NOLOCK) определенно сделали свое дело. Как некоторые из вас указали, это не самый чистый подход. Я не могу действительно запросить все в память, учитывая количество записей, а некоторые столбцы в этой таблице являются двоичными (некоторые записи на самом деле занимают около 1 МБ общих данных).

Другим предложением было запрашивать партии записей одновременно. Это тоже неплохая идея, но она поднимает новую проблему: запросы к базе данных. Прямо сейчас приложение может работать с различными базами данных (Oracle, MySQL, Access и т. Д.). Каждая база данных имеет свой собственный способ ограничения строк, возвращаемых в запросе. Но, может быть, это лучше сохранить для другого вопроса?

Вернемся к теме. Предложение WITH (NOLOCK) определенно относится к SQL Server. Есть ли способ не допустить этого в мой запрос (и, следовательно, помешать ему работать с другими базами данных)? Может быть, я мог бы как-то указать параметр объекта DbCommand? Или я могу указать политику блокировки на уровне базы данных? То есть изменить некоторые свойства в самом SQL Server, чтобы по умолчанию эта таблица не блокировалась?

Ответы [ 8 ]

1 голос
/ 14 февраля 2009

Если вы используете SQL Server 2005+, то как насчет того, чтобы попробовать новую изоляцию снимка MVCC. У меня были хорошие результаты:

ALTER DATABASE  SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE  SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE  SET MULTI_USER;

Это остановит читателей, блокирующих писателей, и наоборот. Он устраняет множество тупиковых ситуаций при минимальных затратах.

1 голос
/ 14 февраля 2009

Первое, что вы можете сделать, это попытаться добавить «WITH (NOLOCK)» во все таблицы, которые есть в вашем запросе. Это снимет блокировку, которую выполняет SQL Server. Пример использования «NOLOCK» в соединении выглядит следующим образом ...

SELECT COUNT(Users.UserID)
    FROM Users WITH (NOLOCK)
       JOIN UsersInUserGroups WITH (NOLOCK) ON 
          Users.UserID = UsersInUserGroups.UserID

Другой вариант - использовать набор данных вместо устройства чтения данных. Устройство чтения данных - это метод «пожарного шланга», который остается подключенным к таблицам, пока ваша программа обрабатывает и в основном обрабатывает таблицу строка за строкой через шланг. Набор данных использует «отключенную» методологию, при которой все данные загружаются в память, а затем соединение закрывается. Ваша программа может затем зациклить данные в памяти, не беспокоясь о блокировке. Однако, если это действительно большой объем данных, возможно, проблемы с памятью.

Надеюсь, это поможет.

1 голос
/ 14 февраля 2009

Это зависит от того, какой уровень изоляции вы используете. Вы можете попытаться выполнить выбор с помощью подсказки With (NoLock), которая предотвратит блокировки чтения, но также будет означать, что считываемые данные могут измениться до завершения транзакции выбора.

0 голосов
/ 14 февраля 2009

Вы должны иметь возможность установить уровень изоляции на уровне .NET, чтобы вам не приходилось включать подсказку WITH (NOLOCK).

Если вы хотите использовать параметр пакетной обработки, вы сможете указать параметр Rowcount на уровне .NET, который сообщит базе данных только о n количестве записей. Установив эти параметры на уровне .NET, они должны стать независимыми от базы данных и работать на всех платформах.

0 голосов
/ 14 февраля 2009

Я не большой поклонник использования подсказок блокировки, так как вы можете получить грязное чтение или другие странности. Пара других идей:

  • Можете ли вы сократить количество строк, чтобы не брать 200 Кб одновременно? Есть ли способ сказать, обработали ли вы строку - флаг, отметку времени - вы могли бы использовать, чтобы сделать запрос? Ваш запрос может быть «ВЫБЕРИТЕ ТОП 5000 ...», каждый раз получая 5 КБ. Более короткие запросы означают более короткие жизненные блокировки.

  • Если вы можете использовать меньшие наборы строк, мне нравится идея DataSet vs. IDataReader. Вы будете загружать данные в память и не использовать SQL-блокировки, но объем памяти может вызвать другие проблемы.

-Брайан

0 голосов
/ 14 февраля 2009

Запрос выполняет блокировку таблицы, поэтому вставки не выполняются.

Мне кажется, что вы держите блокировку на столе, обрабатывая результаты. Вместо этого вы должны загрузить их в какой-либо массив или коллекцию и закрыть соединение с базой данных. Затем обработайте массив.

Кроме того, пока вы делаете выбор, используйте либо: С (NOLOCK) или С (READPAST)

0 голосов
/ 14 февраля 2009

Я считаю, что ваш лучший способ избежать этого - это делать это в SQL, а не в приложении.

Вы можете добавить

ЗАДЕРЖКА ОЖИДАНИЯ '000: 00: 01'

в конце каждой итерации цикла, чтобы предоставить время для запуска других процессов - просто убедитесь, что вы не инициировали транзакцию так, чтобы все остальные процессы все равно были заблокированы

0 голосов
/ 14 февраля 2009

Если вы добавите подсказку WITH (NOLOCK) после имени таблицы в предложении FROM, она должна убедиться, что она не блокируется, и ее не волнует чтение заблокированных данных. Вы можете получить «устаревшие» результаты, если пишете в одно и то же время, но если вас это не волнует, с вами все будет в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...