SQL Azure. Работа с базой данных из портала.

 Соединимся с базой TestDB подобно тому, как мы соединялись с БД master на Рис.6-7 предыдушего поста. Типовые задачи работы с ней сгруппированы внизу левой панели. Модный плиточный интерфейс - это первый пункт (Overview - см. Рис.1 предыдущего поста):

image001

Рис.1

 

Статистика использования - Administration (см. Рис.3 предыдущего поста):

image002

Рис.2

 

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

 

image003

Рис.3

 

Кликаем по New Table и задаем структуру новой таблицы. Можно видеть, что форма ввода очень похожа на интерфейс табличного дизайнера в SSMS:

 

image004

Рис4

 

После сохранения таблицы поменять признак Is Identity у колонки нельзя. Можно досоздать к ней индексы или тут же набить в нее данные, кликнув на соответствующий пункт справа от Columns:

 

image005

Рис.5

 

В ячейках работает Ctrl-C/Ctrl-V. Ширины колонок можно менять, однако, если набить часть записей и сохранить их в таблицу, ширины колонок снова съезжают. Понятно, что этот интерфейс не будет являться основным способом ввода данных в таблицы SQL Azure так же, как никто не пользуется для этих целей, например, SSMS. Так, посмотреть, при случае, подкорректировать.

 

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

 

image006

Рис.6

 

Разумеется, таблицы можно создавать при помощи оператора CREATE TABLE. Его можно выполнить, например, из запросного окна на портале (см. Рис.4 предыдущего поста), которое откроется по нажатию кнопки New Query в верхней строке меню на Рис.6. Особенностью SQL Azure является то, что каждая таблица обязана иметь custered key, т.е. быть организована в виде дерева, а не валяться бесформенной кучей. Это основополагающее ограничение, жалко, что Делани про него не пишет. Мы коснемся его в федерациях. Я так думаю.

 

if object_id('Продукт', 'U') is not null drop table [Продукт]

go

create table [Продукт] (

 ProductID int identity(1, 1) primary key clustered,

 ProductName nvarchar(40) not null,

 CategoryID int foreign key references [Категория](CategoryID),

 UnitPrice smallmoney,

 InStockSince date default sysdatetime()

)

image007

 Рис.7

 

Если теперь кликнуть на Design в левой панели, мы вернемся в список таблиц Рис.6, обновив который (Refresh в верхнем меню), увидим только что созданную таблицу [Продукт]:

 

image008

Рис.8

 

Еще создадим для демонстрации хранимую процедуру, при помощи которой будем добавлять записи в таблицу Категория. Кликaем на Stored Procedures. Процедура uspAddCategory будет принимать три параметра, соответствуюшие полям CategoryName, Description и Picture и состоять из тривиального оператора insert [Категория] (CategoryName, Description, Picture) values (@Category, @Description, @Picture):

 

image009

Рис.9

 

Обратите внимание, что значение по умолчанию для параметра типа varbinary здесь задать не удается, хотя, в принципе, это ничему не противоречит. Портал SQL Azure не любит ни вводить, ни отображать значения типов binary/varbinary, в частности, он не отображает их в панели результатов.

 

Я планирую набить таблицу Категория блобами, чтобы размер базы TestDB достиг установленного ей максимального размера - см. Рис.2 предыдущего поста. В документации сказано, что добавление в нее новых данных становится невозможно, но старые данные остаются доступны на чтение. Мне интересно, можно ли их при этом обновлять. По логике вещей, если это апдейт in-place, который просто перетирает старое значение и не требует увеличения существующего объема за счет, например, сплита страниц, то можно. В целом, апдейт in-place может иметь место, если обновляется не-nullовое поле фиксированной длины, кластерный ключ при этом не затрагивается и ключевые поля некластерного индекса либо не затрагиваются, либо он уникален. Апдейт in-place, по определению, невозможен, если на таблицу повешен триггер или она участвует в репликации или CDC.

 

Можно тупо заполнить varbinary(max) константным байтом до достижения необходимой длины, но это неинтересно. Пусть лучше байты будут случайными. Случайную последовательность байт в T-SQL умеет производить CryptoAPIшная функция CRYPT_GEN_RANDOM(<длина>). Мы касались ее в посте Выбрать случайную запись из таблицы. Замечательная функция, однако входящий параметр <длина> у нее ограничен 8000 байтами. Маловато будет. Для 2008 R2 у меня была писана на ее основе UDF, которая преодолевает это ограничение:

if OBJECT_ID('ufnGenereateRandomVarbinaryMax', 'FN') is not null drop function ufnGenereateRandomVarbinaryMax

go

create function ufnGenereateRandomVarbinaryMax(@n smallint, @kbmb nvarchar(2)) returns varbinary(max) as begin

if @n <= 0 return null

declare @nn bigint = case upper(@kbmb) when 'КБ' then @n * 1024 when 'МБ' then @n * 1024 * 1024 else @n end

declare @MaxSize int = 8000

declare @i int = @nn / @MaxSize; declare @r int = @nn - @i * @MaxSize

declare @b varbinary(max) = cast(replicate(cast(CRYPT_GEN_RANDOM(@MaxSize) as varbinary(max)), @i) as varbinary(max))

if @r <> 0 set @b += CRYPT_GEN_RANDOM(@r)

return @b

end

go

select len(dbo.ufnGenereateRandomVarbinaryMax(10, 'МБ')), @@version

 

image010 

Рис.10

 

Шаблона для создания пользовательской функции в отличие от процедуры в Хьюстоне не предусмотрено, поэтому открываем на портале запросное окно, как на Рис.7, и копируем туда код создания функции из Рис.10:

 

image011

Рис.11

 

Как в сад? Нет, я понимаю, что функция CRYPT_GEN_RANDOM() недетерминирована и все такое, но нормальному SQL Server 2008 R2 SP1 это пополам, а SQL Azure кочевряжится. Это зря она так.

Для справки: что из функциональности SQL Server 2008 не умеет SQL Azure, приведено в BOL.

Идем в пункт Design (слева внизу) -> Views (Сверху) - см. Рис.3 - и создаем новое представление по имени CRYPT_GEN_RANDOM с телом select CRYPT_GEN_RANDOM(8000) as RandomBinary8K:

 

image012

Рис.12

 

Заменяем в пользовательской функции Рис.11 внутренние вызовы функции CRYPT_GEN_RANDOM на обращения к одноименному представлению Рис.12:

 

create function ufnGenereateRandomVarbinaryMax(@n smallint, @kbmb nvarchar(2)) returns varbinary(max) as begin

if @n <= 0 return null

declare @nn bigint = case upper(@kbmb) when 'КБ' then @n * 1024 when 'МБ' then @n * 1024 * 1024 else @n end

declare @MaxSize int = 8000

declare @i int = @nn / @MaxSize; declare @r int = @nn - @i * @MaxSize

declare @b varbinary(max) = cast(replicate(cast( (select RandomBinary8K from CRYPT_GEN_RANDOM) as varbinary(max)), @i) as varbinary(max))

set @b += cast(left((select RandomBinary8K from CRYPT_GEN_RANDOM), @r) as varbinary(max))

return @b

end

 

image013

Рис.13

 

Теперь, когда функция работает, открываем еще один New Query и пишем скрипт наполнения таблички Категория:

 

declare @Picture varbinary(max), @i tinyint = 0

while @i < 20 begin

select @Picture = dbo.ufnGenereateRandomVarbinaryMax(100, 'МБ'), @i += 1

exec uspAddCategory @Picture = @Picture

select @i as Итерация, (sum(reserved_page_count) * 8192.0) / 1024 / 1024 as [Размер базы в метрах] from sys.dm_db_partition_stats

end

 

select CategoryID, CategoryName, Description, Len(Picture) from [Категория]

 

image014

Рис.14

 

Выяснилась любопытная особенность: SQL Azure не моментально обнаруживает, что база превысила отведенный ей лимит:

 

image015

Рис.15

 

image016

Рис.16

 

Работа с "перегретой" базой является нестабильной, соединение несколько раз рвется, тем не менее принципиальная возможность работы сохраняется. Интересно, как с меня в этом случае будут брать деньги: как за 3 гига или за 1? Вообще-то я создавал базу с максимальным размером в 1 ГБ и, по идее, больше этого платить не обязан.

 

Проходит 3-5 минут, прежде чем появляется сообщение об ошибке переполнения при попытке выполнить INSERT или UPDATE:

Msg 40544, Level 20, State 5, Line 1

The database has reached its size quota. Partition or delete data, drop indexes, or consult the documentation for possible resolutions.

 

image017 

Рис.17

 

Операторы SELECT и DELETE продолжают работать. Необходимо либо увеличить MaxSize, как показывалось на Рис.10 предыдущего поста, либо удалить лишнее, приведя БД в пределы MaxSize:

 

delete from [Категория] where Picture is not null

 

После удаления ошибка Рис.17 продолжает выдаваться еще несколько минут на попытки обновления, удаления, создания новых объектов и т.п., пока SQL Azure не сообразит, что объем пользовательских данных в базе уменьшился.

 

Читатели уже обратили внимание, что слева в панели под названием базы данных перечислены открытые активности: окна запросов, создания таблицы, процедуры, представления, окно статистики по базе данных. Кликнув по заголовку My Work, можно собрать их уменьшенные изображения на "рабочем столе", что позволяет, например, быстро закрыть несколько ненужных, не раскрывая их в полный размер.

image018

Рис.18

 

Продолжение следует.

 

Алексей Шуленин