Что делать, если список баз данных в Enterprise Manager открывается очень долго

ПУБЛИКАЦИИ  

Автор: Дмитрий Приходько
По материалам дискуссий на форуме Microsoft SQL Server проекта SQL.RU

Клиентские утилиты SQL Server 2000 (Enterprise Manager) при работе с сервером баз данных используют функцию has_dbaccess ("database_name"), суть которой в том, что она выдает значения 0 или 1, которые определяют, доступна ли база данных в настоящий момент. В клиентских утилитах SQL Server 7.0 данная функция не использовалась, но в серверной части она есть, причём выполняется гораздо медленней, чем у SQL Server 2000.
Разброс по времени выполнения на одну базу у нас наблюдался такой: обычно -4ms, в плохом случае приблизительно 4000ms.

Особенности работы Enterprise Manager 2000 (EM):

Когда EM запрашивает список баз данных сервера, выполняется запрос:


Select ..., has_dbaccess(name) from master..sysdatabases

Этот запрос выполняется без условия where, то есть по всем базам данных. Мало того, этот запрос выполняется в цикле столько раз, сколько есть баз данных на сервере. На нашем сервере было около 100 баз, в результате их список открывался 5 - 10 минут. В SP1 для SQL Server 2000 ситуацию исправили, теперь запрос выполнятся только один раз. Так что рекомендация первая - ставьте сразу SP1 на SQL Server 2000. Но проблема с долгим выполнением функции has_dbaccess осталась.

Что влияет на время выполнения этой функции?
В основном на выполнение этой функции влияют установленные флаги: autoclose и autoshrink. При чём очень сильно. Это замедление заметно и на SQL Server 2000 но в меньшей степени. Исходя из этого, следует рекомендация вторая - снять со всех баз флаги autoclose и autoshrink.
Функция has_dbaccess() на SQL Server 7.0 может быть заблокирована процессом восстановления из Backup. При чем, когда процесс восстановления завершается, оба коннекта падают, восстановление базы часто завершается с ошибкой и его приходится повторять. Данная ситуация происходит не всегда, но часто. Особенно эта ситуация была острой до появления SP1. Рекомендация третья - не используйте EM 2000 без SP1 для работы с SQL Server 7.0, когда идёт восстановление баз данных.
Общий вывод такой: функция has_dbaccess() опасна для MS SQL Server 7.0. Скорее всего, происходит взаимная блокировка в базе master, которая некорректно разрешается сервером.

Зарисовки на тему has_dbaccess()

Функция has_dbaccess() используется еще в нескольких местах.
1. В Query Analyzer когда вы выбираете базу из списка.
2. В ODBC драйвере - настройка подключения.
То есть потенциально любой пользователь, у которого стоит клиент SQL Server 2000 может нарушить процесс восстановления из Backup.

К слову, а как Query Analyzer 2000 работает с SQL Server 6.5? Там же такой функции нет. А очень просто. C начала делается запрос, содержащий функцию has_dbaccess(name). Естественно сервер выдает ошибку. Ошибка обрабатывается на клиенте и выдается второй запрос просто:

 
select name from master..sysdatabases.

В итоге повторюсь:
1. Всегда снимайте со всех баз флаги autoclose и autoshrink.
2. Установите на клиентских компьютерах SP1 для SQL Server 2000.
3. Администрируйте SQL Server 7.0 с помощью EM от 7.0. Для этого мы держим отдельный компьютер с клиентом 7.0.
После этого можно жить, время работы запросов резко уменьшается (но вероятность падения в процессе восстановления базы остаётся, при чём, иногда даже полностью падает сервер).
Рекомендация последняя - если все базы под SQL Server 7.0 не используйте клиента для SQL Server 2000, если же начат процесс перехода на SQL Server 2000 - не затягивайте его, побыстрее переводите все базы данных на новую версию.

Прилагаю скрипт. Те базы, которые вы увидите, проверьте функцией sp_dboption 'name' на соответствие представленным выше рекомендациям.


set nocount on
if (select object_id('tempdb..#bases')) is not null exec( 'drop table #bases')
create table #bases (t_name varchar(255), t_time int , dba int)
go
declare @start datetime, @finish datetime,
@my_base varchar(255),
@dba int
select @my_base = char (0)
while (1=1)
begin
set rowcount 1
select @start = getdate()
select @my_base = name,
@dba = has_dbaccess(name)
from master..sysdatabases
where name > @my_base
order by name
if @@rowcount = 0
begin
set rowcount 0
break
end
set rowcount 0

select @finish = getdate()
insert #bases (t_name, t_time, dba)
select @my_base, datediff(ms,@start, @finish), @dba
end
select cast(t_name as varchar (30) ), t_time, dba from #bases where t_time > 20

Дополнительная информация по решению описанной в статье проблемы содержиться в этом документе:
FIX: Opening the Database Folder in SQL Server Enterprise Manager 2000 Takes a Long Time


Редактция: Александра Гладченко  2001г.

ПУБЛИКАЦИИ

Скачать электронную карту Ангарска бесплатно
Сайт управляется системой uCoz