InMemory – потрясающая концепция, и мне посчастливилось узнать о ней от своих друзей в индустрии через блоги. Она содержит глубокие концепции и иногда сложно понять, как все строится. В этом блоге мы рассмотрим концепцию оптимистической многоверсионной конкурентности в SQL Server и как она реализуется.
Оптимистическая многоверсионная конкурентность – это концепция в SQL Server, которая позволяет нескольким транзакциям одновременно получать доступ и изменять данные без блокировки друг друга. Это достигается созданием нескольких версий данных и позволяет каждой транзакции работать со своей собственной версией.
Давайте начнем с создания базы данных и таблицы для экспериментов. Вот скрипт:
USE [master]
GO
-- Этот оператор работает только с SQL Server 2016
-- Измените его соответствующим образом, если вы используете более ранние версии
DROP DATABASE IF EXISTS [InMem_OLTP]
GO
CREATE DATABASE [InMem_OLTP] ON PRIMARY
( NAME = N'InMem_OLTP_data', FILENAME = N'C:\DATA\InMem_OLTP_data.mdf',
SIZE = 20480KB, MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB),
FILEGROUP [InMem_OLTP_InMemory] CONTAINS MEMORY_OPTIMIZED_DATA DEFAULT
( NAME = N'InMem_OLTP_InMemory', FILENAME = N'C:\Data\InMem_OLTP_mopt',
MAXSIZE = UNLIMITED)
LOG ON
( NAME = N'InMem_OLTP_log', FILENAME = N'C:\DATA\InMem_OLTP_log.ldf',
SIZE = 20480KB, FILEGROWTH = 10%)
GO
-- Создание таблицы для экспериментов
USE [InMem_OLTP]
GO
CREATE TABLE dbo.SalesOrder_inmem
(
order_id INT IDENTITY NOT NULL,
order_date DATETIME NOT NULL,
order_status tinyint NOT NULL,
amount FLOAT NOT NULL,
CONSTRAINT PK_SalesOrderID PRIMARY KEY NONCLUSTERED
HASH (order_id) WITH (BUCKET_COUNT = 10000)
) WITH ( MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)
GO
INSERT INTO dbo.SalesOrder_inmem VALUES
('1/1/2010',1,1000),
('1/1/2011',1,2000),
('1/1/2012',1,3000),
('1/1/2013',1,4000),
('1/1/2014',1,5000)
Теперь давайте разберемся с оптимистической частью многоверсионной конкурентности. Мы создадим сценарий с двумя сессиями и наблюдаем, как SQL Server обрабатывает конкурентность.
-- Сессия 1
BEGIN TRANSACTION
INSERT INTO dbo.SalesOrder_inmem VALUES
('1/1/2015',1,6000)
-- Сессия 2
SELECT * FROM dbo.SalesOrder_inmem
В приведенном выше сценарии у нас есть две сессии. В сессии 1 мы вставляем новую запись в таблицу. В сессии 2 мы пытаемся прочитать из таблицы. Однако мы видим только существующие 5 записей, а 6-я запись, вставленная в сессии 1, не видна. Это происходит потому, что транзакция в сессии 1 все еще открыта, и SQL Server создал версию данных, чтобы гарантировать, что запрос в сессии 2 не блокируется. Как только мы фиксируем транзакцию в сессии 1, дополнительная запись автоматически появляется в сессии 2.
-- Сессия 1
COMMIT
-- Сессия 2
SELECT * FROM dbo.SalesOrder_inmem
Теперь давайте подробнее рассмотрим многоверсионность. Мы обновим запись и наблюдаем различные версии данных.
-- Сессия 1
BEGIN TRANSACTION
UPDATE dbo.SalesOrder_inmem WITH (SNAPSHOT)
SET amount = 10000
WHERE order_id = 6
-- Сессия 2
SELECT * FROM dbo.SalesOrder_inmem
В приведенном выше сценарии мы обновляем значение amount в сессии 1. Однако обновленное значение не видно в сессии 2 до тех пор, пока транзакция в сессии 1 не будет зафиксирована. Это демонстрирует возможность SQL Server поддерживать несколько версий записей в таблице InMemory.
Надеюсь, этот блог-пост помог вам более ясно понять, как работают таблицы InMemory в оптимистической модели конкурентности. Если у вас есть вопросы или вам нужна большая ясность по любому аспекту, не стесняйтесь обращаться ко мне.
Счастливого кодирования!