Анонс встречи RuBI PASS Chapter: использование SQL Server Parallel Data Warehouse (PDW) и Hadoop для построения хранилищ данных (DWH)

27 июня в 19:00 в Москве пройдет очередная встреча Russian BI PASS Chapter. Состоится она как обычно в Microsoft Technology Center, м. Белорусская. Докладчик: Андрей Резник, Microsoft.

Microsoft SQL Server Parallel Data Warehouse (PDW) – это высокопроизводительная платформа для организации аналитического хранилища данных (DWH) от десятка до сотен ТБ, обеспечивающая отличную производительность и масштабируемость.Parallel Data Warehouse использует архитектуру обработки больших объемов данных, состоящую в распределении данных и параллельной обработки на разных серверах (узлах). Каждый из узлов использует свои собственные процессоры, память и дисковые ресурсы. Такой подход называется обработкой с массовым параллелизмом (MPP).

Мы рассмотрим базовые принципы, заложенные в PDW, его архитектуру, состав серверов, рекомендации к проектированию схемы данных. Также взглянем на Hadoop, экосистему для построения распределенных систем, и его интеграцию с PDW.

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

Вход бесплатный, но требуется предварительная регистрация по следующей ссылке: http://ineta.ru/rubi/Meeting/2013-06-27-19-00. При себе необходимо будет иметь паспорт, чтобы пройти в бизнес центр. До встречи! :)

Генерация скриптов для создания и удаления объектов SQL Server и с помощью Powershell

В свой предыдущей статье я показал, как можно использовать мастер SQL Server Management Studio для генерации скриптов для различных объектов SQL Server. Мастер обладает большим набором возможностей, но также и рядом недостатков. Например, мы видели, что нельзя легко сгенерировать скрипты для всех объектов из определенной схемы, кроме как вручную указать все эти объекты. В этой статье мы рассмотрим другой подход к генерации скриптов – программный. Для этого мы будем использовать Powershell, мощное и гибкое средство для управления любыми Windows машинами или сервисами, в том числе и SQL Server.

Самый простой способ – запустить Powershell прямо из SSMS.

У вас откроется консоль Powershell, в которой уже будет загружен модуль SQLPS и открыт путь до нашей базы данных. Здесь можно просматривать и работать с объектами также, как и с файлами и папками. Например, с помощью следующего набора команд мы перейдем к таблицам в нашей базе данных, получим список всех таблиц в переменную и для первой таблицы в списке сгенерируем скрипт.

# Переходим к списку таблиц
cd Tables
 
# Считываем все таблицы в массив
$tables = Get-ChildItem
 
# Выводим информацию о первом элементе
$tables[1]
 
# Для первой таблицы генерируем скрипт
$tables[1].Script()

У вас должно получиться что-то подобное, как на скриншоте снизу.

Но, если мы хотим, например, сгенерировать не скрипт создания, а скрипт удаления указанной таблицы. Для этого потребуется создать объект класса Microsoft.SqlServer.Management.Smo.ScriptingOptions, указать у него определенные свойства (а их у объекта большое множество) и снова вызвать метод Script у таблицы, в который в качестве параметра передать объект со свойствами.

# Создаем новый объект класса Microsoft.SqlServer.Management.Smo.ScriptingOptions
$script_options = New-Object ('Microsoft.SqlServer.Management.Smo.ScriptingOptions')
 
# У этого объекта выставляем свойство ScriptDrops в значение true
$script_options.ScriptDrops = $true
 
# Снова запускаем метод Script с указанными опциями
$tables[1].Script($script_options)

Мы даже можем указать имя файла и сохранить сгенерированный скрипт в файле.

# Указываем файл, куда будет сохранен скрипт
$file_name = "C:\Temp\MyScript.sql"
 
# Перенаправляем вывод с консоли в указанный файл
$tables[1].Script($script_options) > $file_name

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

# Для всех таблиц, имя которых начинается на Pro, сгенерировать скрипты с опциями, указанными в $script_oprions и выложить скрипт для каждого для каждого отдельного объекта в папку C:\Temp в формате <Имя схемы>.<Имя таблицы>.sql
foreach ($t in $tables | Where-Object { $_.Name.StartsWith("Pro") }) { $t.Script($script_options) > "C:\Temp\$($t.Schema).$($t.Name).sql" }

Как мы видим, набор возможностей практически не ограничен за одним исключением. Набивать эти команды в консоли крайне неудобно. Гораздо удобнее написать отдельный скрипт и вызывать его по мере необходимости. Хочу привести пример отдельного скрипта на Powershell для генерации скриптов создания всех таблиц в базе с ограничениями, внешними ключами и т.п. в один большой скрипт с разделителями.

# Загружаем модуль для работы с SMO объектами.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
 
# Объявляем переменные и указываем имя сервера, имя базы данных и путь до файла, куда будет сохранен скрипт создания всех таблиц.
$srv_name = "(local)"
$db_name = "AdventureWorks2012"
$file_name = "C:\Temp\CreateAllTables.sql"
 
# Объявляем объект класса Microsoft.SqlServer.Management.Smo.Server.
$srv = New-Object('Microsoft.SqlServer.Management.Smo.Server') $srv_name
 
# Получаем объект нужной нам базы данных.
$db = $srv.Databases[$db_name]
 
# Создаем объект класса Microsoft.SqlServer.Management.Smo.Scripter, который будет выполнять всю работу по созданию скриптов.
$scripter = New-Object('Microsoft.SqlServer.Management.Smo.Scripter') $srv
 
# Указываем, что в скрипт нужно включать все DRI объекты (Declarative Referential Integrity: ограничения, внешние ключи и т.п.).
$scripter.Options.DriAll = $true
# Включать в скрипт создание индексов.
$scripter.Options.Indexes = $true
# Включать в скрипт добавление расширенных свойств.
$scripter.Options.ExtendedProperties = $true
 
# Указывать в скрипте разделитель GO между командами создания объектов.
$scripter.Options.ScriptBatchTerminator = $true
$scripter.Options.NoCommandTerminator = $false
 
# Указываем, что сохранять скрипт необходимо в файл.
$scripter.Options.FileName = $file_name
$scripter.Options.ToFileOnly = $true
$scripter.Options.AppendToFile=$true
 
# Для всех таблиц, имя которых начинается на Pro, сгенерировать скрипты и добавить их в указанный файл.
foreach ( $t in $db.Tables | Where-Object { $_.Name.StartsWith("Pro") } ) {
    $scripter.Script($t)
}

На этом все. Я постарался привести максимально полезные примеры, от которых вы сможете отталкиваться при написании своих скриптов на Powershell.

Генерация скриптов для создания и удаления объектов SQL Server из SSMS

Довольно часто возникает потребность генерации скриптов для создания или удаления различных объектов MS SQL Server. Например, для создания идентичной по структуре базы данных на другом сервере или для сохранения перед внесением каких-либо серьезных изменений. В SQL Server Management Studio есть мощный строенный механизм генерации скриптов. Для этого достаточно щелкнуть правой клавишей мыши на нужной базе данных и выбрать пункт Tasks -> Generate Scripts для запуска мастера генерации скриптов.

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

Следующим этапом будет выбор объектов, для которых мы хотим сгенерировать скрипты. Можно оставить опцию по умолчанию, чтобы сгенерировать скрипты для всех объектов в базе данных, либо выбрать только нужные.

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

На следующей странице находится, пожалуй, самое важное – опции генерации скриптов. От них зависит, что в итоге будет сгенерировано для указанных нами раньше объектов. Мы не будем рассматривать возможность публикации сгенерированных скриптов на веб сервис, а ограничимся только сохранением их локальной копии.

Здесь мы можем выбрать путь, куда будет выложен один большой скрипт для всего, либо для каждого отдельного объекта. Также формат файла: Unicode или ANSI. И, несмотря на то, что для сгенерированного скрипта есть возможность не сохранять его в файл, а либо скопировать в буфер обмена, либо открыть его сразу в новом окне SSMS, я не рекомендую использовать эту опцию, т.к. для достаточно больших скриптов это не будет работать, а каким получится скрипт зачастую нельзя предугадать. Однако, если вы заранее знаете, что скрипт получится маленьким, то это вполне оправданно.

Также на этой странице находится самая важная кнопка, Advanced, при нажатии на которую откроется окно различных настроек генерации.

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

  1. По умолчанию генерируются только скрипты создания. Есть опция генерации команд на удаления, либо и то и другое одновременно.
  2. Версия SQL Server для которой создается скрипт. Эта опция может быть полезна, если вы хотите создать объекты на более ранней версии сервера, где какие-то возможности не поддерживаются или немного отличаются. В этом случае скрипты будут сгенерированы таким образом, чтобы не вызывать ошибку при их запуске.
  3. Также есть возможность при генерации включить в скрипты команды создания пользователей и их прав на указанные объекты.
  4. Вы можете контролировать, включить ли в скрипт только описание указанных объектов, либо добавить команды вставки данных, либо и то и другое одновременно. Очень полезно, когда есть необходимость для какой-либо таблицы или таблиц сформировать скрипт на вставку данных.
  5. По умолчанию при генерации скриптов таблиц не генерируются команды создания индексов, что также может быть полезно в некоторых случаях.

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

Что нового в SQL Server 2014

Microsoft SQL Server 2014 был анонсирован 3 июня на основном вступительном докладе Microsoft TechEd 2013. В этом месяце будет доступна для скачивания публичная сборка CTP1, а окончательная версия выйдет ориентировочно в начале 2014 года. Если откинуть в сторону все громкие маркетинговые заявления, что же действительно нового и полезного появляется в этом релизе?

  • In-Memory OLTP (кодовое название Hekaton) – встроенный в движок механизм, позволяющий создавать таблицы с данными, оптимизированные для непосредственного размещения в оперативной памяти, а также для хранимых процедур становится доступна возможность компилирования их в машинный код. Все это позволяет получить выигрыш в производительности в несколько раз. Наверное, это самая главная и ожидаемая «фишка» новой версии.
  • Колоночные индексы (Column Store Indexes) теперь становятся обновляемыми.
  • Появляется возможность расширения буферного пула на SSD.
  • Будут изменения непосредственно в движке исполнения запросов, что опять же должно будет положительно сказаться на производительности.
  • В AlwaysOn теперь будет поддерживаться до 8 реплик вместо 4х.
  • Улучшения при перестроении индексов в режиме онлайн.
  • Через Resource Governor теперь можно будет управлять IO ресурсами.
  • Также обещают возможность более гибкой выдаче прав, например, администратор сможет управлять системой и не иметь доступа к важным данным.
  • В SSMS появится мастер миграции БД с обычного сервера в Windows Azure Infrastructure Services.
  • Резервное копирование в Azure Storage.
  • Интеграция AlwaysOn с Windows Azure Infrastructure Services: появится возможность иметь реплики в облаке, а также мастер в SSMS для их легкого развертывания.

Также нас порадовали тем, что выйдет Windows Server 2012 R2 и SQL Server сможет воспользоваться новыми возможностями этой ОС:

  • Поддержка до 640 логических процессоров и до 4 TB оперативной памяти (для виртуальных машин поддерживается до 64 логических процессоров и до 1 TB RAM).
  • Виртуализация сетей облегчит миграцию SQL Server между ЦОД.
  • Появится возможность более гибко управлять дисковыми ресурсами. Например, автоматически вынести наиболее запрашиваемые данные на быстрое хранилище, а данные, к которым обращаются редко, наоборот, на более медленные диски.

Скорее всего, появится еще несколько более мелких изменений. Если честно, меня список возможностей новой версии очень сильно впечатляет. Без сомнения, это будет очень интересный и функциональный релиз. Однако, многие возможности изменят текущее представление о том, как лучше настраивать сервер, проектировать базы данных и оптимизировать запросы. Наверное, это и к лучшему: больше возможностей, более гибкий подход к проектированию инфраструктуры.

Материалы с конференции DevCon 2013

2 недели назад в подмосковных Яхонтах прошла очередная конференция DevCon 2013. Выкладываю материалы моих докладов.

Как читать план запроса в SQL Server и на что обращать внимание

В докладе идет речь о том, что такое план запроса; о различных операторах, с которыми можно встретиться, с чего начать анализ плана, на что обращать внимание и как можно выявить “узкое место” в запросе.

Презентация: http://olontsev.ru/download/DevCon2013_Query_Plans.pdf

Скрипты с демонстрациями: http://olontsev.ru/download/Query_Plans_Demo_Scripts.zip

Особенности использования хранимых процедур и функций в SQL Server

Эта сессия об особенностях, с которыми можно столкнуться при использовании хранимых процедур и функций в SQL Server, и как это может повлиять на производительность ваших запросов.

Презентация: http://olontsev.ru/download/DevCon_2013_UDFs_and_SPs.pdf

Скрипты с демонстрациями: http://olontsev.ru/download/UDFs_and_SPs_Demo_Scripts.zip

Записи докладов можно посмотреть по указанной ссылке (в скором времени должны выложить на http://www.techdays.ru/): http://www.msdevcon.ru/online

Ну и напоследок ответ на самый главный вопрос конференции: в чем секрет белки? J

Преобразование в Base64 и обратно

Хочу поделиться способом преобразования строки в Base64 и обратно. Сразу оговорюсь, что способ не самый быстрый, но главное его преимущество в том, что он работает прямо «из коробки» без применения специальных CLR функций. Нам потребуется тестовая база данных и таблица для примера:

use [master];
go
 
if db_id('Base64_test') is not null
begin
	alter database [Base64_test] set single_user with rollback immediate;
	drop database [Base64_test];
end
go
 
create database [Base64_test];
go
 
use [Base64_test];
 
create table [dbo].[Base64_test] (
	[plain_text] nvarchar(max),
	[base64_text] nvarchar(max)
);
go
 
insert into [dbo].[Base64_test] ([plain_text], [base64_text])
values (N'My Test String', N'TQB5ACAAVABlAHMAdAAgAFMAdAByAGkAbgBnAA==');
go

Пример конвертации строки в Base64:

-- Конвертируем значение переменной
declare @value varbinary(max);
set @value = cast(N'My Test String' as varbinary(max));
select cast(N'' as xml).value('xs:base64Binary(sql:variable("@value"))', 'varchar(max)') as [encoded_value];
go
 
-- Конвертируем значение столбца в таблице
select cast(N'' as xml).value('xs:base64Binary(sql:column("plain_text"))', 'varchar(max)') as [encoded_value]
from (
	select cast([plain_text] as varbinary(max)) as [plain_text]
	from [dbo].[Base64_test]
) as tmp;
go

Пример обратного преобразования:

-- Конвертируем значение
select cast(cast(N'' as xml).value('xs:base64Binary("TQB5ACAAVABlAHMAdAAgAFMAdAByAGkAbgBnAA==")', 'varbinary(max)')  as nvarchar(max)) as [decoded_value];
go
 
-- Конвертируем значение переменной
declare @value varchar(max)
set @value = 'TQB5ACAAVABlAHMAdAAgAFMAdAByAGkAbgBnAA=='
select cast(cast(N'' as xml).value('xs:base64Binary(sql:variable("@value"))', 'varbinary(max)')  as nvarchar(max)) as [decoded_value];
go
 
-- Конвертируем значение столбца в таблице
select cast(cast(N'' as xml).value('xs:base64Binary(sql:column("base64_text"))', 'varbinary(max)') as nvarchar(max)) as [decoded_value]
from [dbo].[Base64_test];
go

SQL Server 2014 Hekaton

Вчера на TechEd North America анонсировали SQL Server 2014, который должен будет выйти в начале 2014 года. В скором времени можно будет скачать публичный предварительный релиз SQL Server 2014 CTP1. А пока давайте чуть прольем свет на одну из самых ожидаемых возможностей в новом SQL Server известную под кодовым названием Hekaton (в переводе с греческого означает число 100).

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

Начиная с этого дня я начинаю публиковать серию статей про Hekaton, а с выходом CTP1 и полноценные демонстрации этой очень интересной технологии. Оставайтесь на связи! J

SQL Server Enterprise Edition Advanced Scanning

Мы знаем, что Enterprise редакция SQL Server содержит некоторые улучшения, которые при определенных условиях позволяют выполнять операции более оптимально, чем в Standard редакции. Одной из таких вещей является Advanced Scanning, которая позволяет нескольким запросам на сканирование делить одну операцию физического чтения с диска. Также можно встретить другое название этой особенности: Merry-go-Round Scan.

Например, у нас есть большая таблица Table1 состоящая из 1 000 000 страниц. Пользователь UserA начинает выполнять инструкцию T-SQL, которая требует сканирования таблицы. В тот момент, когда выполнилось сканирование 200 000 страниц пользователь UserB подключается и начинает другой запрос, который также требует сканирование Table1. Для сканирования после 200 001-ой страницы компонент Database Engine запланирует всего одно физическое чтение и будет возвращать полученные строки обоим планам выполнения. После сканирования 500 000 страниц пользователь UserC подключается и также запрашивает все данные из таблицы Table1. Теперь операция физического сканирования уже делится между 3мя запросами. Как только сканирование закончится для пользователя UserA, оно продолжится для пользователей UserB и UserC, но уже с 1-ой страницы и соответственно до 200 000 для UserB и до 500 000 для UserC.

В чем смысл этой оптимизации. Если у вас имеются очень большие таблицы, которые не вмещаются целиком в оперативную память и их сканирование приводит к «вымыванию» буферного пула и такие сканирования идут часто и параллельно, то такая оптимизация поможет снизить давление на буферный пул и не делать сканирование несколько раз.

Для демонстрации давайте создадим достаточно большую таблицу с кластеризованным индексом в БД AdventureWorks2012.

use
[AdventureWorks2012];
go
 
select
    [DatabaseLogID],
    [PostTime],
    [DatabaseUser],
    [Event],
    [Schema],
    [Object],
    [TSQL],
    [XmlEvent]
into [dbo].[BigDatabaseLog]
from [dbo].[DatabaseLog];
go
 
insert into [dbo].[BigDatabaseLog]
(
    [PostTime],
    [DatabaseUser],
    [Event],
    [Schema],
    [Object],
    [TSQL],
    [XmlEvent]
)
select
    [PostTime],
    [DatabaseUser],
    [Event],
    [Schema],
    [Object],
    [TSQL],
    [XmlEvent]
from [dbo].[DatabaseLog];
go 200
 
create clustered index [IX_CL_DatabaseLogID]
on [dbo].[BigDatabaseLog]
(
    [DatabaseLogID] asc
) on [PRIMARY];
go

Также стоит отметить, что Advanced Scanning работает только в том случае, если нет требования, чтобы поток данных был отсортирован. Например, как в следующем плане запроса:

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

Дополнительно стоит отметить, что у меня получилось провести указанный эксперимент только для сканирования кластеризованного индекса, который целиком не помещается в буферный пул. Я ограничивал размер максимальной памяти в SQL Server 400 мегабайтами. В двух следующих ситуациях вышеуказанное НЕ работало:

  1. При сканировании heap таблицы (без кластеризованного индекса) данные всегда возвращались в одном порядке.
  2. Также, если таблица целиком закэширована в буферном пуле, результаты также возвращались в одном порядке, но это ничему не противоречит, т.к. тяжелых операций чтения с диска при этом нет, а только логические чтения из буферного пула.

Статистические функции STDEV, STDEVP, VAR, VARP

Среди функций агрегации в SQL Server присутствуют STDEV, STDEVP, VAR и VARP, которые могут вызвать вопросы, что это такое, как и когда их применять. Для начала я приведу формулы, по которым идем расчет указанных функций. Функции взяты из математической статистики.

STDEV возвращает статистическое среднеквадратическое отклонение всех значений в указанном выражении.

 — дисперсия;  — i-й элемент выборки;  — объём выборки;  — среднее арифметическое выборки:

STDEVP возвращает статистическое среднеквадратичное отклонение совокупности всех значений в указанном выражении.

VAR возвращает статистическую дисперсию всех значений в указанном выражении. Значение равно (квадрат значения, возвращаемого функцией STDEV).

VARP Возвращает статистическую дисперсию для заполнения всех значений в указанном выражении (квадрат значения, возвращаемого функцией STDEVP).

Т.к. функции VAR и VARP фактически дублируют STDEV и STDEVP, то сосредоточимся только на последних. Перепишем формулы их вычисления в чуть более понятный на мой взгляд вид.

Stdevp = sqrt( ((x1-xmean)^2 + (x2-xmean)^2 + … + (xn-xmean)^2)/n )

Stdev = sqrt( ((x1-xmean)^2 + (x2-xmean)^2 + … + (xn-xmean)^2)/(n-1) )

По сути эти функции показывают насколько в среднем значения отличаются от арифметического среднего. Теперь давайте рассмотрим небольшой пример их применения. Возьмем простую таблицу со столбцом типа int, 3мя записями и рассчитаем для них значения функций.

USE [tempdb];
GO
 
IF OBJECT_ID('tempdb.dbo.test', 'U') IS NOT NULL
    DROP TABLE [dbo].[test];
GO
 
CREATE TABLE [dbo].[test] (
    [d] [int] NOT NULL
);
GO
 
INSERT INTO [dbo].[test] ([d]) VALUES (1), (2), (3);
GO
 
SELECT
    AVG([d]) AS [avg]
    ,STDEV([d]) AS [stdev]
    ,STDEVP([d]) AS [stdevp]
FROM [dbo].[test];
GO


Значение STDEV на небольших выборках, как мы видим может быть более точным, нежели STDEVP (по сути исключается из расчетов одно значение, которое либо само является средним, либо близко к среднему). Но на больших выборках они могут быть очень близки.

Т.е. эти функции удобно применять, когда требуется вычислить все значения в таблице, которые сильно отклоняются от среднего. Есть даже такое правило трех сигм (), которое утверждает, что практически все значения выборки будут лежать в диапазоне 3х сигм от среднего.

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

USE [tempdb];
GO
 
IF OBJECT_ID(‘tempdb.dbo.test’, ‘U’) IS NOT NULL
    DROP TABLE [dbo].[test];
GO
 
CREATE TABLE [dbo].[test] (
    [d] [int] NOT NULL
);
GO
 
INSERT INTO [dbo].[test] ([d]) VALUES (1), (2), (1), (1), (0), (1), (1), (2), (1), (1), (15);
GO
 
SELECT
    [d]
    ,CASE WHEN ABS([d] - AVG([d]) OVER() ) &gt; 3 * STDEV([d]) OVER() THEN 1 ELSE 0 END IsLargeThan3Sigma
FROM [dbo].[test];
GO

Установка offline документации для SQL Server 2012 на Windows 8

SQL Server 2012 поставляется без локальной версии всем привычных нам Books Online. Хорошо это или плохо вопрос спорный. Несомненно, эра широкополосного интернета пришла и одним из главных плюсов онлайн документации – это ее более актуальное состояние: онлайн версия обновляется чаще, чем локальная. Но, offline версия на мой взгляд удобнее в работе и она быстрее. В этой заметке я хотел бы рассказать, как установить локальную версию документации для SQL Server 2012 на Windows 8.

В первую очередь необходимо ее скачать по указанной ссылке http://www.microsoft.com/en-us/download/details.aspx?id=347. На момент написания заметки это версия по состоянию на декабрь 2012, но по этой же ссылке должна будет в будущем быть доступна и более свежая версия. Итак, мы скачали файл SQLServer2012Documentation_December2012_EN.exe размером чуть более 200 мегабайт. Запускаем его. Файл представляет из себя самораспаковывающийся архив. Распаковываем его во временную директорию.

По окончании распаковки мы получаем следующее сообщение.

Далее запускаем Microsoft Help Viewer.

На вкладке Manage Content выбираем Installation source с диска и указываем файл C:\Temp\SQLServer2012Documentation_December2012_EN\HelpContentSetup.msha.

Нажимаем напротив всех пунктов Add и жмем кнопку Update.

Все, процесс установки локальной версии документации завершен.