Дождитесь закрытия соединений, прежде чем восстанавливать базу данных SQL Server.

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

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

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

Обе мои машины работают под управлением SQL Server 2008 64 Bit Standard Edition.


person lstanczyk    schedule 25.06.2009    source источник


Ответы (5)


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

person lstanczyk    schedule 29.06.2009

Вероятно, у вас есть измененная настройка базы данных для одного пользователя или режима администратора, в которой есть «С НЕМЕДЛЕННЫМ ОТКАТОМ». Это то, что выгоняет пользователей. Удалите этот пункт, и он будет ждать, пока они уйдут (но не остановит также появление новых).

RE: Ваш Kill sProc: возможно, вы захотите взглянуть на опцию «С НЕМЕДЛЕННЫМ ОТКАТОМ».

Что касается предотвращения новых подключений: в прошлом я отключил логины (основной сервер) пользователей приложения, подождал до 10 минут, проверяя каждую минуту, чтобы убедиться, что все вышли. После этого я делаю ИЗМЕНЕНИЕ БАЗЫ ДАННЫХ... С НЕМЕДЛЕННЫМ ОТКАТОМ, а затем на любую функцию OPS, которую необходимо выполнить.

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

DENY CONNECT TO SomeDBUserName;
person RBarryYoung    schedule 25.06.2009
comment
на самом деле я использую процедуру хранения, которая выгоняет всех: ALTER PROCEDURE [dbo].[USP_GETEXCLUSIVE] @dbname varchar(100) AS DECLARE @KILL_ID int DECLARE @QUERY VARCHAR(320) DECLARE GETEXCLUSIVE_CURSOR CURSOR FOR SELECT A.SPID FROM SYSPROCESSES A JOIN SYSDATABASES B ON A.DBID=B.DBID WHERE B.NAME=@DBNAME OPEN GETEXCLUSIVE_CURSOR FETCH NEXT FETEXCLUSIVE_CURSOR INTO @KILL_ID WHILE(@@FETCH_STATUS =0) BEGIN SET @QUERY = 'KILL' + CONVERT(VARCHAR,@KILL_ID) EXEC (@QUERY) FETCH NEXT FROM GETEXCLUSIVE_CURSOR INTO @KILL_ID END CLOSE GETEXCLUSIVE_CURSOR DEALLOCATE GETEXCLUSIVE_CURSOR - person lstanczyk; 25.06.2009
comment
Большой вопрос в том, как не дать базе данных принимать новые подключения на время, пока я жду. - person lstanczyk; 25.06.2009
comment
Я думаю, это то, чего он хочет избежать. В Biztalk есть режим отключения, который позволяет вам закрывать службы для новых подключений, но позволяет завершить существующие процессы, а затем отключать их, как только они простаивают. Я думаю, ему нужна аналогичная функциональность в SQL Server. - person SqlRyan; 26.06.2009
comment
rwmnau: то, что я описываю (DENY CONNECT), должно обеспечить это. Текущие соединения должны быть в порядке, просто не допускайте новых. - person RBarryYoung; 27.06.2009

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

Триггеры входа

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

Жизненный цикл триггера входа в систему очень прост: пользователь подключается к серверу Sql, срабатывает триггер, открывается неявная транзакция, а затем все зависит от вас! Если по какой-либо причине вы хотите отклонить попытку входа на сервер Sql, просто введите оператор 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: Настройте БД на одного пользователя и восстановите журналы.

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

Радж

person Raj    schedule 27.06.2009

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

person Remus Rusanu    schedule 26.06.2009

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

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

person SqlRyan    schedule 26.06.2009