12.2.26

Можно ли использовать динамические административные представления в режиме совместимости 80 (MSSQL 2000)?

Автор: Paul Randal, A DBA myth a day: (13/30) you cannot run DMVs when in the 80 compat mode (T-SQL Tuesday #005);

Нельзя выполнять динамические административные представления (DMV) в режиме совместимости 80.

ЛОЖЬ

Для начала, существует большая путаница относительно того, что означает режим совместимости. Означает ли это, что базу данных можно восстановить/присоединить к серверу SQL Server 2000? Нет. Это означает, что некоторые аспекты синтаксического разбора T-SQL, поведения планов запросов, подсказки и некоторые другие вещи ведут себя так же, как в SQL Server 2000 (или 2005, если вы устанавливаете значение 90 на экземпляре 2008).

В SQL Server 2008 вы можете использовать ALTER DATABASE SET COMPATIBILITY_LEVEL для изменения уровня совместимости; в предыдущих версиях используется sp_dbcmptlevel. Чтобы увидеть, что контролирует уровень совместимости, обратитесь к статье электронной документации Уровень совместимости инструкции ALTER DATABASE (Transact-SQL).

Уровень совместимости не влияет на физическую версию базы данных — именно она повышается при обновлении и предотвращает восстановление/присоединение базы данных к предыдущей версии, поскольку у них есть максимальная физическая версия, которую они могут понять. См. мою статью в блоге  Search Engine Q&A #13: Difference between database version and database compatibility level для получения более подробной информации, а также Msg 602, Level 21, State 50, Line 1 для получения подробной информации о сообщениях об ошибках, которые вы получаете при попытке присоединить/восстановить базу данных в предыдущей версии.

Но я отвлёкся, как обычно :-)

Одна из вещей, которая выглядит так, будто не работает, — это использование DMV в режиме совместимости 80. Вот простой скрипт для демонстрации с использованием SQL Server 2005:

CREATE DATABASE [DMVTest];
GO
USE [DMVTest];
GO
CREATE TABLE [t1] ([c1] INT);
CREATE CLUSTERED INDEX [t1c1] on [t1] ([c1]);
INSERT INTO [t1] VALUES (1);
GO

EXEC sp_dbcmptlevel DMVTest, 80;
GO

SELECT * FROM sys.dm_db_index_physical_stats (
    DB_ID (N'DMVTest'), -- идентификатор базы данных
    OBJECT_ID (N't1'),  -- идентификатор объекта
    NULL,               -- идентификатор индекса
    NULL,               -- идентификатор секции
    'DETAILED');        -- режим сканирования
GO

И действительно полезная ошибка, которую я получаю в ответ:

Msg 102, Level 15, State 1, Line 2
Incorrect syntax near '('.

Насколько это невероятно полезно? Это точно указывает на проблему — нет.

Примечание: После написания этого я понял, что сам пал жертвой собственного мифа! DMV полностью поддерживаются в режиме совместимости 80. Что не поддерживается, так это вызов функции (например, OBJECT_ID) в качестве одного из параметров DMV. Спасибо Аарону Бертрану за указание на это! 

Вот трюк с использованием функций в качестве параметров. Вы переключаете контекст на базу данных с уровнем совместимости 90 или выше — и затем вы можете направить DMV на базу данных с уровнем совместимости 80.

Очень круто. Проверьте:

USE [master];
GO

SELECT * FROM sys.dm_db_index_physical_stats (
    DB_ID (N'DMVTest'),
    OBJECT_ID (N'DMVTest..t1'),
    NULL,
    NULL,
    'DETAILED');
GO

И это работает, даже если база данных DMVTest находится на 80-м уровне совместимости.

На что нужно обратить особое внимание — убедитесь, что вы используете правильный идентификатор объекта. Если бы я оставил второй параметр как OBJECT_ID ('t1'), он бы попытался найти идентификатор объекта таблицы t1 в базе данных master. Если он не найден, будет использовано значение NULL, что заставит DMV выполняться для всех таблиц в базе данных DMVTest. Если случайно в master есть таблица t1, её идентификатор объекта, скорее всего, отличается от идентификатора таблицы t1 в DMVTest, и тогда DMV завершится ошибкой.

И sys.dm_db_index_physical_stats — это не совсем DMV (динамическое административное представление); это динамическая административная функция, которая выполняет огромный объём работы для возврата результатов — поэтому вы хотите ограничить её только теми таблицами, которые вас интересуют. См. моей статье в блоге «Внутри sys.dm_db_index_physical_stats» для получения подробной информации о том, как она работает и насколько дорогостоящей может быть.

Итак, вам нужно использовать новую опцию трёхчастного имени в OBJECT_ID начиная с SQL Server 2005, чтобы убедиться, что вы захватываете правильный идентификатор объекта при переходе между контекстами баз данных.

Другой способ сделать это — использовать переменные и предварительно присвоить им значения, что можно сделать непосредственно из базы данных в режиме совместимости 80:

DECLARE @databaseID INT;
DECLARE @objectID   INT;

SELECT @databaseID = DB_ID (N'DMVTest');
SELECT @objectID   = OBJECT_ID (N't1');

SELECT * FROM sys.dm_db_index_physical_stats (
    @dbid,
    @objid,
    NULL,
    NULL,
    'DETAILED');
GO

Суть: очередной миф повержен!

Комментариев нет:

Отправить комментарий