Дождитесь закрытия соединений, прежде чем восстанавливать базу данных SQL Server - PullRequest
7 голосов
/ 25 июня 2009

У меня есть веб-приложение, которое использует две базы данных. DB1 Пользователи выполняют свои операции CRUD (создание, чтение, обновление, удаление). База данных DB2 - это база данных только для чтения на другом сервере, которую я использую для составления отчетов. Каждый час мой DB1 сохраняет журналы транзакций, и в DB2 у меня есть задание, которое восстанавливает их в этой DB2, чтобы поддерживать их в актуальном состоянии.

Проблема, с которой я сталкиваюсь, заключается в том, что если в DB2 есть пользователи, запускающие отчеты (что происходит довольно часто), они отключаются от сервера sql, поскольку я получаю эксклюзивный доступ для восстановления базы данных. Время, необходимое для восстановления каждого журнала, составляет от 1 до 4 минут.

Как реализовать, давайте назовем это функцией wait-n-restore, когда моя работа ожидает завершения запросов пользователей, прежде чем переключить базу данных на монопольный доступ и восстановить журнал?

Обе мои машины работают под управлением 64-разрядной стандартной версии SQL Server 2008

Ответы [ 5 ]

2 голосов
/ 30 июня 2009

Большая часть моей проблемы заключалась в использовании объединенных соединений - в этом случае, даже если не было выполнено ни одного отчета, соединения оставались в живых. Я изменил строку подключения, чтобы в пуле подключений было установлено значение false, и проверял наличие открытого подключения пользователя к вашей отчетной БД в цикле до значения 0. К счастью, мне не нужно создавать триггер для отказов пользователей.

1 голос
/ 27 июня 2009

Я предполагаю, что ваше восстановление происходит как работа. Тогда вам нужен триггер входа в систему. Вот как вы создаете триггер входа в систему:

Триггеры входа в систему

Триггер входа в систему срабатывает при установлении сеанса. В этот момент возникает событие LOGON.

Жизненный цикл триггера входа в систему очень прост: пользователь подключается к Sql Server, триггер срабатывает, неявная транзакция открывается, и тогда дело за вами! Если по какой-либо причине вы хотите отказать в попытке войти на Sql Server, просто выполните инструкцию ROLLBACK, и все готово.

Вот пример триггера входа в систему:

USE master;
GO
CREATE LOGIN security_login WITH PASSWORD = 'P@ssw0rd'; 
GO
GRANT VIEW SERVER STATE TO security_login;
GO
CREATE TRIGGER connection_deny_trigger
ON ALL SERVER WITH EXECUTE AS 'security_login'
FOR LOGON
AS
BEGIN
<*Your conditional code goes here*>
    ROLLBACK;
END;

Вы можете определить свою работу, чтобы сделать это:

  • Шаг 1: Включить триггер входа в систему
  • Шаг 2: Проверка на открытого пользователя подключение к вашей отчетной БД в цикл до значения 0

    SELECT COUNT(*) from sysprocesses where spid in(
    SELECT session_id FROM sys.dm_exec_sessions WHERE is_user_process = 1) AND
    dbid= DB_ID('YourReportingDatabase')
    
  • Шаг 3: Установите DB для одного пользователя и восстановить ваши журналы

  • Шаг 4. Сброс БД до многопользовательского режима и отключение триггера входа в систему

Raj

1 голос
/ 25 июня 2009

Возможно, у вас есть режим изменения настроек базы данных для одного пользователя или администратора, в котором указано «WITH IMMEDIATE ROLLBACK». Это то, что выгоняет пользователей. Уберите это предложение, и оно будет ждать, пока они уйдут (но не остановит и новых).

RE: Ваш Kill sProc: вы можете посмотреть опцию «С НЕМЕДЛЕННЫМ ОТКЛОНЕНИЕМ».

Что касается предотвращения новых подключений: то, что я делал в прошлом, это отключил вход в систему (основной сервер) пользователей приложения, подождите до 10 минут, проверяя каждую минуту, чтобы увидеть, все ли отсутствуют. После этого я выполняю команду ALTER DATABASE ... WITH IMMEDIATE ROLLBACK, а затем выполняю любую функцию OPS, которую необходимо выполнить.

Мне повезло в том, что логины всегда были одноразовыми логинами пользователей приложений (т. Е. Логинами SQL только для этой цели). Если вы не можете этого сделать, то единственное, о чем я могу подумать в данный момент, это быть отказывать в разрешении CONNECT Пользователям БД (субъект базы данных). а потом ОТЗЫВАТЬ ДЕНИ позже. Я никогда не делал так, но это должно выглядеть примерно так:

DENY CONNECT TO SomeDBUserName;
0 голосов
/ 26 июня 2009

Требуется ли резервное копирование каждый час или другой способ репликации будет отвечать вашим потребностям лучше, чем настраиваемый вами процесс? Вы можете выполнить доставку журналов, которую можно настроить на доставку каждый час, и SQL Server будет позаботиться об этом, блокируя пользователей во время восстановления журналов.

Я вижу вашу проблему, и я не думаю, что SQL Server обладает нужной вам функциональностью (блокировка новых соединений, в то же время позволяя завершить существующие соединения), но есть и другие обходные пути, которые могли бы дать вам то же репликации и может лучше удовлетворить ваши бизнес-требования.

0 голосов
/ 26 июня 2009

Можно ли перенаправить отчетность на другое имя базы данных? Если да, вы можете создавать снимки базы данных DB2 и запускать отчеты из этих снимков. После каждого восстановления журнала вы создаете новый снимок и помечаете его где-то как «текущий снимок», и все новые отчеты запускаются для этого снимка. При отправке нового журнала создается новый снимок, и новые отчеты сопоставляются с новым снимком, в то время как старые, работающие отчеты остаются в предыдущем снимке. Когда последний отчет сделан со старым снимком, и больше нет пользователей, ссылающихся на него, его можно удалить. Таким образом, ни один отчет никогда не прерывается за счет дополнительного хранилища: каждый новый журнал приводит к тому, что старые моментальные снимки запускаются «копирование при записи» затронутых страниц.

...