Quantcast
Channel: Немножко всего .. из жизни администратора ms sql server
Viewing all articles
Browse latest Browse all 43

In-Memory tables. Таблицы в памяти - просто.

$
0
0

Начиная с MSSQLServer 2014 Microsoftпредоставила к использованию технологию таблиц In-Memory, в 2016 данная технология получила продолжения и улучшения. Технология подразумевает, что определяется таблица, которая оптимизирована для нахождения в памяти сервера, что позволяет повысить производительность обработки данных в данной таблице, за счет быстроты работы данных в памяти и исключения задержек, связанные с вводом\выводом (хотя здесь есть свои нюансы). Постараюсь описать все нюансы и возможности в одной статье, чтобы не искать по разным страницам msdn, немного много, но зато все в одном.


Итак, требования
Чтобы вы могли в MSSQLServerиспользовать In-Memoryтаблицы, то должны проверить следующие требования:
-  64 – разрядный MS SQL Server 2014и выше редакции Enterprise, Developer или Evaluation
- достаточное объем самой оперативной памяти для данных и версионности строк, так же это зависит о нагрузки на использования таблиц в памяти
- Необходимо включить быструю инициализацию файлов, т.е предоставить учетной записи MSSQLServerправо на «Perform volume maintenance tasks» в локальных политиках сервера. Это требования желательное, в противном случае может сыграть отрицательно на производительность.

Немного теории.

Основным хранилищем для таблиц In-Memoryявляется основная память, т.е вся память находится в памяти. Строки записываются и считываются только из памяти. Для отказоустойчивости данный таблиц дублируются на диск, но можно настроить, чтобы таблица была только в памяти, это не создает дополнительной нагрузки на диск, но и все данные в таблицах хранятся до перезагрузки сервера. Все операции с таблицами транзакционны и соответствуют классификации ACID(atomic, consistent, isolated, durable) . Транзакционность выполняется за счет версионность строк, т.е. каждая изменённая строка создает новую версию строки, к которой будет дальнейшее обращение. Это позволяет практически сократить блокировки в таблицах.

Одновременно с появлением In-Memoryтаблиц, появился новый тип индексов –HASHиндексы. Создание HASH-индекса осуществляется с помощью внутренней hashфункции, которая является единственной для всего mssqlserverи является детерминированной, из этого следует, что несколько значений ключей индекса могут быть связаны с одним сопоставление хеш индекса, появляется конфликт хеша. Большое число конфликтов может отрицательно связаться на операции чтения. Использование hashиндексов нужно быть аккуратным, они используются только когда в предикате условия указаны все поля hashиндекса. К примеру: создали hashиндекс на Имя, Фамилию, а в запросе используется только Фамилия, то наш Hashиндекс работать не будет, нужно указать в Запросе и имя и Фамилию. Так же в HASHиндексах запрещен поиск по диапазону.

На таблицах In-Memoryмогут быть определены индексы как кластерные, не кластерные, так и новые HASHиндексы одновременно, возможно несколько HASHиндексов. Единственное замечание: все индексы создаются при создании таблицы инструкцией CREATETABLE, далее новые индексы создаются только через пересоздание таблицы.

Пример вполне можно создать данную таблицу:
CREATETABLE [dbo].[TblInMem_Index]
(
       [id] [int] NOTNULL,
       [val1] [nchar](36)COLLATE Cyrillic_General_BIN2 notNULL,
       [val2] [nchar](36)COLLATE Cyrillic_General_BIN2 NOTNULL,

INDEX[Hass_ind] NONCLUSTEREDHASH
(
       [val2]
)WITH (BUCKET_COUNT= 1048576),

INDEX [idx2] NONCLUSTERED
(
       [val1] ASC,
       [val2] ASC
),
 PRIMARYKEYNONCLUSTERED
(
       [id] ASC
)
)WITH (MEMORY_OPTIMIZED=ON,DURABILITY= SCHEMA_AND_DATA )

GO

В которой мы определили три индекса:

Кластерные по полю Id
Не кластерный [idx2]
Hash индекс [Hass_ind].

Так же существуют два вида таблиц: таблицы оптимизированные с параметром DURABILITY=SCHEMA_AND_DATA – это таблицы, которые размещены в памяти, но и существуют на диске, второй тип таблиц это таблицы с параметром DURABILITY= SCHEMA_ONLY, это значит , что данные находятся в памяти и доступны только до перезагрузки сервера, так же эти данные не будут доступны и при создание резервной копии, с параметром DURABILITY=SCHEMA_AND_DATA данные в таблице In-Memoryбудут доступны после восстановления из резервной копии.

Параметр WITH(MEMORY_OPTIMIZED=ON,DURABILITY= SCHEMA_ONLY)определяется для всей таблицы: вне зависимо есть ли в ней новые HASHиндексы или кластерные, при значении параметра DURABILITY=SCHEMA_ONLY- данные хранятся до перезагрузки ms sql server.

Обращение к таблицам In-Memoryпроисходит с помощью стандартных инструкций T-SQLс явным указанием уровня изоляции SNAPSHOT, REPETABLEREADили SERIALIZABLEили помощью так называемых процедур скомпилированные в собственном коде (NativeCompiledStoredProcedures). В обращение к таблицам In-Memoryесть много ограничений, следует это учитывать.

Процедуры, скомпилированные в собственном коде (NativeCompiledStoredProcedures) –это наиболее быстрый доступ к таблицам In-Memory, но и имеющий много особенностей. На «физическом» уровне после создания NativeCompiledпроцедуры мы имеем dllбиблиотеку, которая компилируется один раз при создании или при рестарте сервера.

Особенности NativeCompiledпроцедур:

- код процедуры определяется разово, далее ее можно изменить только через пересоздание
- внутри процедуры транзакция определяется как BEGIN ATOMIC, что определяет свои требования
- объекты, на которые ссылается процедура, не могут быть изменены при наличие данных процедур
- нельзя просмотреть актуальный план данных процедур
- нельзя получить статистику выполнения данных процедур
- для соединения таблиц внутри хранимой процедуры используется только NETEDLOOP
- не используется параллелизм
- план выполнения NativeCompiledпроцедуры определяется в момент ее создания, в MSSQLServer2016 для перекомпиляции процедуры можно использовать процедуру sp_recompile

Пример создания NativeCompiledпроцедурs:
createprocedure [dbo].[InsertIntoMemoryTable](@i int)
withnative_compilation,schemabinding,executeasowner
as
beginatomicwith (transactionisolationlevel=snapshot,language=N'English')
      
       declare @id int=convert(int,RAND()*1000000000)
       declare @val1 nchar(36)
       set @val1=convert(nvarchar(36),newid())COLLATECyrillic_General_BIN2 
       declare  @val2 nchar(36)
       set @val2='text'+convert(nchar(8),@i)COLLATE Cyrillic_General_BIN2
      
       insertinto [dbo].[TblInMem1]
             values (@id,@val1,@val2)
        
end

withnative_compilation,schemabinding,executeasowner- При определение данной процедуры обязательно
beginatomicwith (transactionisolationlevel=snapshot,language=N'English') так же обязательные параметры, требования ATOMIC

После создания данной процедуры в каталоге баз данных будет создана папка xtpдалее папка номер базы данных, внутри которой будут файлы нашей процедуры:
xtp_t_9_1973582069_183184666479020.xml
xtp_t_9_2037582297_183184668414697.c
xtp_t_9_2037582297_183184668414697.dll- сама dllбиблиотека
xtp_t_9_2037582297_183184668414697.obj
xtp_t_9_2037582297_183184668414697.out
xtp_t_9_2037582297_183184668414697.pdb
Содержимое которых вы можете посмотреть, оно связано с определением процедуры на коде C. Файлы вы можете изменить\удалить, но mssqlserverпридется их заново создать, что потребует время при вызове процедуры.

В имени файла выше 9 это номер базы данных, 2037582297 – номер объекта из sysobjects.

Кстати, выше процедура будет работать только в MSSQLServer 2016, т.к в MSSQL  Server 2014 текстовые поля все должны быть в UNICODформате. В MSSQLServer 2014 нужно немного поменять определение

set @val2=N'text'+convert(nchar(8),@i)COLLATECyrillic_General_BIN2

иначе будет ошибка:
Msg 12329, Level 16, State 103, Procedure InsertIntoMemoryTable1, Line 21
The data types char(n) and varchar(n) using a collation that has a code page other than 1252 are not supported with natively compiled stored procedures.


Ограничение при работе с таблицами In-Memory:

Ниже описаны наиболее явные ограничения в MSSQLServerна таблицы In-Memory, которые чаще всего мы привыкли использовать при обычных diskтаблицах. Приведена только часть ограничений, полные ограничения можно изучить в msdn.

Общие ограничения для MSSQL 2014 и MSSQL 2016:
Для баз данных с таблицами In-Memoryзапрещены свойство AUTO_CLOSE
Запрещена операция CREATE DATABASE  с параметром ATTACHE_REBUILD_LOG
Запрещена операция создания DATABASESNAPSHOT
Операции проверки целостности DBCCCHECKDB, CHECKTABLEпропускают таблицы In-Memory
Не поддерживаются межбазовые запросы и транзакции, а также обращения со связанными серверами
Не поддерживаются вычисляемые столбцы в таблицах In-Memory
Не поддерживается репликация для таблиц In-Memory
Не поддерживаются столбцы SPARSE
Не поддерживаются операции TRUNCATE
Не поддерживается сжатие, секционирование таблиц
Не поддерживается репликация, зеркалирование
В NativeCompiledпроцедурах Функции MIN и MAX не поддерживаются для типов nvarchar, char, varchar, varchar, varbinary и binary
В NativeCompiledпроцедурах DISTINCT не поддерживается в предложении ORDER BY 
В NativeCompiledпроцедурах не поддерживаются WITH TIES и PERCENT в предложении TOP 
В NativeCompiledпроцедурах не поддерживается многостроковая вставка через INSERT.
В NativeCompiledпроцедурах не поддерживается SELECTINTO
В NativeCompiledпроцедурах не поддерживается инструкция CASE
Таблицы In-Memoryс SCHEMA_ONLYвбазах данных в группе доступности AlwaysOnбудут пустыми.
Не поддерживаются типы данных: datetimeoffset, geography, geometry, hierarchyid, rowversion,xml, sql_variant, определяемые пользователем типы
Операция MERGE только в качестве назначения
Доступ из модулей CLR запрещен к таблицам In-Memory
Табличные подсказки
Фильтруемые индексы не поддерживаются
Не поддерживаются курсоры в Native Compiled процедурах

Ограничения MSSQL 2014

все ограничения выше +
Использование только UNICODтипов данных
Использование Collation _Binдля символьных полей индексов
Ограничение общего объем всех таблиц в памяти не должен превышать 250 Гб
Не авто обновляется статистика для таблиц In-Memory, необходимо вручную обновлять
Не поддерживаются LOB объекты


Пример создания таблиц.

Для начала нужно иметь базу данных, далее в базе данных создается файловая группы базы данных для таблиц In-Memory

USE [master]
GO
ALTERDATABASE [INMemDB] ADDFILEGROUP [InMemory_filegroup] CONTAINS MEMORY_OPTIMIZED_DATA
GO

Добавляем новый файл группы в нашу файловую группу для таблиц In-Memory
USE [master]
GO
ALTERDATABASE [INMemDB] ADDFILE
( NAME =N'InMemoryFile',FILENAME=N'C:\Data\InMemory2014\InMemoryFile')
TOFILEGROUP [InMemory_filegroup]
GO

В этот момент в указанном каталоге создается каталог InMemoryFile с содержимым аналогично каталогу FileStream:

Далее создаем нашу таблицу:

CREATETABLE [dbo].TblInMem
(
       [id] [int] NOTNULL,
       [val1] [char](20)NULL,
       [val2] [char](20)NOTNULL,
        PRIMARYKEYNONCLUSTEREDHASH
(
       [id],
       [val2]
)WITH (BUCKET_COUNT=1000000)
)

WITH (MEMORY_OPTIMIZED=ON,DURABILITY= SCHEMA_AND_DATA);

Создали, ОК, далее. СТОП далее, нужно уточнить, что выше создалась таблица в MSSQLServer2016, в 2014 она не создается, т.к в 2014 в таблицах In-Memoryвозможно использовать только UNICODEтипы данных
В 2014 создаем таблицу:

CREATETABLE [dbo].[TblInMem1]
(
       [id] [int] NOTNULL,
       [val1] [nchar](36)COLLATECyrillic_General_CI_AS NULL,
       [val2] [nchar](36)COLLATECyrillic_General_BIN2  NOTNULL,

 PRIMARYKEYNONCLUSTEREDHASH
(
       [id],[val2]
)WITH (BUCKET_COUNT= 1048576)
)WITH (MEMORY_OPTIMIZED=ON,DURABILITY= SCHEMA_AND_DATA )


Таблица определена с одним hashиндексом.
Немного об синтаксисе создания таблицы:

PRIMARYKEYNONCLUSTEREDHASH  – создается не кластерный HASH индекс, HASH индекс поддерживается только для In-Memory таблиц, без него мы не сможем создать нашу таблицу в памяти, обязательный параметр.
WITH(BUCKET_COUNT=1000000) – так же обязательный параметр при создание HASHиндексов, указывается так называемые количество контейнеров для hashиндексов, которое желательно должно быть в 2 раза более уникальных значений нашего индекса. Если выбрано неоптимальное значение то, может привести к деградации производительности при обращении к данной таблице. 

Далее сделаем тест на загрузку данных.

Я сделал несколько простых тестов на вставку:
setnocounton
go
declare @start datetime2(7)=SYSDATETIME()
declare @stop datetime2(7)
select @start

declare @i int=0
while @i<1000000
begin

 begintry
       insertinto [dbo].[TblInMem]
       values (convert(int,RAND()*1000000000),convert(varchar(36),newid()),'text'+convert(nchar(8),@i))
       set @i=@i+1
 endtry
 begincatch
   print @i
 endcatch

end

set @stop =SYSDATETIME()
select @stop
selectDATEDIFF(ss,@start,@stop)
go
setnocountoff
go
Использовал таблицы, созданные выше в пример создания таблицы,
CREATETABLE [dbo].[TblInMem1]
(
       [id] [int] NOTNULL,
       [val1] [nchar](36)COLLATE Cyrillic_General_CI_AS NULL,
       [val2] [nchar](36)COLLATE Cyrillic_General_BIN2  NOTNULL,

 PRIMARYKEYNONCLUSTEREDHASH
(
       [id],[val2]
)WITH (BUCKET_COUNT= 1048576)
)WITH (MEMORY_OPTIMIZED=ON,DURABILITY= SCHEMA_AND_DATA )
 структура во всех тестах была одинакова, за исключением менял параметр DURABILITY, а так же изменял поля в MSSQLServer2016.

Результаты тестирования:
Parameters of Test
MS SQL Server 2014
average val, sec
MS SQL Server 2016
average val, sec
Table with DURABILITY = SCHEMA_AND_DATA
585/584/584/588
585,25
626/637/610/616
622,25
Table with DURABILITY = SCHEMA_AND_DATA with no UNICODE column, BIN


610/604/585/606/
601,25
Table with DURABILITY = SCHEMA_AND_DATA , UNICODE, не BIN поле


588/604/614/617
605,75
Table with DURABILITY = SCHEMA_ONLY
38/37/39
38
47/55/52
51,3
Table with DURABILITY = SCHEMA_ONLY with no UNICODE column, BIN


44/46/49
46,3
Table with DURABILITY = SCHEMA_ONLY , UNICODE, не BIN поле


53/50/52
51,7
Native procedure with DURABILITY = SCHEMA_AND_DATA
560/553/559
557,3
564/584/581
576,3
Native procedure with DURABILITY= SCHEMA_ONLY
28/26/30/
28
38/38/37
37,7
Disk table
614/605/596
605
633/637/634
634,67

По результатам тестирования:

Наиболее интересные результаты выделил желтым цветом. В целом вставка в In-Memoryтаблиц смотрится хорошо, можно заметить, что в MSSQLServer 2014 она даже быстрее чем в 2016, видно из-за того, что в 2016 было снято множество ограничений, что немного повлияло на скорость. По таблице заметен выигрыш NativeCompiledпроцедур.

Тесты «TablewithDURABILITY = SCHEMA_AND_DATA, UNICODE, не BINполе» -это тестирование в MSSQLServer 2016 с полями таблицы не UNICODEи не BINcollationвидно, что они не сильно влияют на скорость, но заметно что не BINи не UNICODEполей и при DURABILITY = SCHEMA_AND_DATAданные чуть ниже, возможно из-за меньших типов данных при хранении.

По результатам TablewithDURABILITY = SCHEMA_AND_DATAи Disktableрезультаты не сильно отличаются в пользу In-memoryтаблиц. У меня disktableтаблицы и файлы файловой группы In-Memoryрасположены на одних дисках, так что все упирается в них.  На практике, для данных таблиц In-Memoryжелательно выделять отдельный диск, а лучше SSDдиск, тогда производительность таблиц In-Memoryбудет заметна. К примеру, у вас есть база данных 1 тб, вы покупаете отдельный диски 120 Гб , строите Raidмассив, и располагаете на них вашу файловую группу In-Memory, то в данном случае мы получим довольно хороший выигрыш.

Тесты запускались больше количество раз, чем указано выше в таблице, все результаты были в этих границах.

Наблюдение таблиц In-Memory

Ниже несколько запрос по получению информации по таблицам In-Memoryна вашем сервере:

Получение общей информации, сколько таблицы занимают в памяти:
--получение общей информации, объем таблиц в памяти
SELECTtype 
,name 
,pages_kb/1024 AS pages_MB  
FROMsys.dm_os_memory_clerksWHEREtypeLIKE'%xtp%' 

В общем, объекты, связанные с таблицами In-Memory, выделяются префиксов xtp.

По таблицам
---распределение в памяти по таблицах
SELECTobject_name(t.object_id)AS [Table Name] 
     ,memory_allocated_for_table_kb 
 ,memory_allocated_for_indexes_kb 
FROMsys.dm_db_xtp_table_memory_stats dms JOINsys.tables t  
ON dms.object_id=t.object_id 
WHERE t.type='U' 

Размер файлов таблиц In-Memory на диске:
--размер файлов на диске, размер папки InMemoryFile на диске
SELECTSUM(df.size)* 8 / 1024 AS [On-disk size in MB] 
FROMsys.filegroups f JOINsys.database_files df  
   ON f.data_space_id=df.data_space_id 
WHERE f.type=N'FX' 

Потипамфайлов
SELECTstate_desc 
 , file_type_desc 
 ,COUNT(*)AS [count] 
 ,SUM(CASE 
   WHENstate= 5 AND file_type=0 THEN 128*1024*1024 
   WHENstate= 5 AND file_type=1 THEN 8*1024*1024 
   WHENstateIN(6,7)THEN 68*1024*1024 
   ELSE file_size_in_bytes 
    END)/ 1024 / 1024 AS [on-disk size MB]  
FROMsys.dm_db_xtp_checkpoint_files 
GROUPBYstate, state_desc, file_type, file_type_desc 
ORDERBYstate, file_type 

Для диагностики таблиц In-Memoryв плане достаточности параметра BUCKET_COUNT, есть запрос:
SELECTobject_name(hs.object_id)AS'object name',
       i.name as'index name',
       hs.total_bucket_count,
       hs.empty_bucket_count,
       floor((cast(empty_bucket_count asfloat)/total_bucket_count)* 100)AS'empty_bucket_percent',
       hs.avg_chain_length,
       hs.max_chain_length
FROMsys.dm_db_xtp_hash_index_stats AS hs
JOINsys.indexesAS i ON hs.object_id=i.object_idAND hs.index_id=i.index_id

Необходимо обратить на значения:
empty_bucket_count – указывает число пустых контейнеров в  hash индексе.

Меньше 10, то число значение BUCKET_COUNT слишком малое, идеально значение более 33 и более.

avg_chain_length –указывает среднюю длину цепочек в hashконтейнерах. Если значение avg_chain_length больше 10 и empty_bucket_percent больше 10, то, вероятнее всего, имеется много одинаковых значений ключей индекса и использование некластеризованного индекса будет более целесообразным. Средняя длина цепочки, равная 1, является оптимальной.

Заключение.

Технология In-Memoryдовольно полезное дополнение, которое позволяет получить огромную производительность в базах данных на MSSQLServer. Но, как и везде, для этого нужно правильно организовать и построить вашу базу данных, просто взять и включить опцию In-Memoryна ваших таблицах недостаточно, в некоторых случаях мы можем вообще получить деградацию.

Необходим глубокий анализ структуры таблиц и данных, запросов, а может и архитектуры ваших приложений. Для новых систем и приложений, лучше сразу планировать поддержку данной технологии, это будет легче чем потом пытаться подстроить базу под In-Memoryтехнологию, тем более в MSSQLServer 2016 снято много ограничений.


Так что тестируйте, используйте, улучшайте. 

Viewing all articles
Browse latest Browse all 43

Trending Articles