Bu makalede 2014 yılında yayınlanan In-Memory Table OLTP(Online Transaction Processing) Engine yapısından bahsedeceğim.
In-Memory Table, adından da anlaşılacağı üzere, verileri fiziksel disk yerine RAM üzerinde saklandığı özel bir tablo türüdür. Bu yapı, geleneksel disk tabanlı tablolara kıyasla çok daha hızlı veri okuma ve yazma performansı sunar çünkü disk erişimi esnasında yaşanan darboğaz sorununa alternatif bir çözüm sunmuştur. Verinin, buffer pool içinde cache’lenmesi, düşük gecikme(low latency) ve yüksek throughput en büyük avantajlarıdır. Özellikle yüksek hacimli veri işleyen, çok sayıda eş zamanlı işlem gerçekleştiren veya gerçek zamanlı yanıt süresi gerektiren sistemlerin kullanımı oldukça yaygındır. (Örneğin: finansal platformlar, IoT işlemleri, sipariş işlemleri) Avantajlarını göz önünde bulundurarak o zaman her ortama bunu yapalım diyebiliriz 🙂 pahalı bir donanım olan RAM ‘den sınırsız bir şekilde elinizde bulunduruyor olmanız gerekebilir çünkü In-Memory bulunduğu ortama yüksek RAM maliyeti, kendine has filegroup yapısı ile yönetimsel zorluklar, failover sürelerinin uzaması gibi dezavantajları da beraberinde getirmektedir.
In-Memory Tabloların kendine özgü kısıtlamaları vardır şimdi bunlardan biraz bahsedelim;
- (n)varchar(max) ve varbinary(max) data tiplerini destekler fakat xml, clr, (n)text, and image data tiplerini desteklemez.
- SELECT INTO, CTE gibi ifadeler native derlenmiş procedurlerde kullanılamaz.
- MERGE INTO komutu, hedef tablo in-memory olduğunda desteklenmez
- Bir tabloda maksimum 8 index oluşturulabilir ve Filter Index, Included columns gibi özellikler desteklenmez, computed columns desteklenmez, Full-Text Indexes kullanılamaz. Tablo oluşturulurken indexlerde oluşturulur sonrasında CREATE INDEX, DROP INDEX komutları doğrudan desteklenmez. Yani tablo oluştururken 3 index planladınız ama sonrasında planlar değişti 2 index daha atmanız gerekiyor o zaman yeni tablo oluşturup indexleri oluştururken atacaksınız ve eski 3 indexli olan tablodan veriyi 5 indexli olan tabloya taşıyacaksınız 🙂
- Replication, Mirroring, Database Snapshots, CDC, Data Compression, Contained Databases gibi özellikler desteklenmez.
In-Memory OLTP Engine temelde 3 amacı vardır.
- Data Page’ler memory’nin içerisine yüklendiğinde disk üzerinde depolanmaz.
- In-Memory Çalışma Mekanizması latch ve lock mekanizmasından özgürdür.
- Latch: Bellek içindeki veri yapılarının tutarlılığını sağlamak için kullanılan lock mekanizmasından daha hızlı ve düşük maliyetli, CPU üzerinde çalışır.
- Büyük ve yoğun iş yükü olan OLTP sistemleri için, yüzlerce hatta binlerce eş zamanlı(concurrency) olarak kullanıcıların işlem yapmasını destekler.
In-Memory OLTP data ’ları ayrı bir Filestream-Based filegroup içinde depolar bunu şu şekilde açıklayabiliriz; disk persistency(kalıcılık) için, filestream tabanlı bir memory-optimized filegroup içinde özel bir formatta saklanır. Bu yapı bellekte hızlı erişim sağlarken, checkpoint işlemleriyle diske yazılmasını da garanti eder. Bu kapsamda In-Memory tablo kullanımında checkpoint önemli bir faktör oluşturmaktadır bu konuyu “Smart Backup” makalemizde detaylı bir şekilde anlatmıştım okumanızı tavsiye ederim. Yani veriler hem RAM ‘de hem de filestream filegroup altında .xtp dosyaları ile diske yazılır.
- In-Memory OLTP için oluşturulan filegroup türü özel olarak “MEMORY_OPTIMIZED_DATA” özelliğiyle tanımlanır ve sadece In-Memory tabloların verilerini saklamak için kullanılır, normal filegroup ‘lar bu işlevi göremez.
SCHEMA_AND_DATA seçeneği ile tablo içerisindeki yapılan işlemler transaction log içerisinde depolanarak dataların tamamen kalıcı(durable) olmasını sağlar. Yani sunucunun planlı olmayan bir şekilde restarta gitmesi veya belirlenemeyen bir sebepten crash yaşanması durumunda dataların kurtarılmasına olanak sağlar. Bunun için tablo oluşturulurken en az bir PK(Primary Key) olmalıdır; bu şartı da biraz daha açacak olursak In-Memory OLTP tablolarında veri erişimi ve bellek yönetimi için satırların benzersiz şekilde tanımlanması gerekir, bu yüzden SQL Server en az bir PRIMARY KEY zorunluluğu koymuştur.
Tablo tanımı sırasında WITH(MERMORY_OPTIMIZED=ON) ifadesini kullanarak bu tablo RAM ‘de çalışacak şekilde işaretlenir, örneklerini yapacağız J
SCHEMA_ONLY seçeneği ile oluşturulan In-Memory tablolar, yalnızca tablo yapısını(şemayı) kalıcı tutar, ancak veri kalıcılığı sağlanmaz. Bu nedenle, veriler transaction log’a yazılmaz ve sunucunun planlı olmayan bir şekilde restarta gitmesi veya belirlenemeyen bir sebepten crash yaşanması durumunda tüm veriler kaybolur. Bu yapıda veriler geçici olduğundan, PRIMARY KEY tanımlamak zorunlu değildir.
Memory-optimized tablo en fazla 8 indexi destekler, bu sınırlama bellek kullanımını kontrol altında tutmak ve performansı korumak için konulmuştur.
Memory-optimized tablo, AlwaysOn Failover Clusters and Availability Groups, Log Shipping ve SQL Failover Cluster için desteklenir. Unutulmamalıdır ki failover sonrası tüm data memory içine tekrardan yükleneceği için failover süresi artacaktır.
In-Memory OLTP, satır versiyonlama (row versioning) kullanan bir sistemdir. Yani bir satır güncellendiğinde, eski satır silinmez; bunun yerine yeni bir versiyon oluşturulur. Her satır yaşam süresi boyunca iki zaman bilgisi taşır.
- BeginTs: Satırın oluşturulduğu zamanı,
- EndTs: Satırın geçersiz olduğu (silindiği veya güncellendiği) zamanı gösterir.
Bu yapı, eşzamanlılık problemlerini azaltmak ve okuma-yazma işlemlerini kilitlemeden(lock) yönetmek için tasarlanmıştır. Yani sistem, satırı değiştirmek yerine yeni bir sürümle devam eder, bu da performans ve tutarlılık avantajı sağlar.
Son olarak, In-Memory tabloların potansiyelinden en iyi şekilde faydalanmak için native compiled stored procedürler ile birlikte kullanılması önerilir. Çünkü bu procedürler derlenmiş kod olarak çalışacağı için SQL ‘in yorumlama sürecini atlayarak ciddi performans kazancı sağlar. In-Memory tabloları kullanım amacımız maksimum veri işleme ve maksimum hız olduğu için bizim için önemli bir etken oluşturacaktır. Aşağıya bunun bir örneğini bırakıyor olacağım.
Diğer tablo yapıları ile kıyaslandığında daha hızlı ve verimli yapıdadır. Aşağıdaki örnekte diğer tablolar ile kıyaslama örneklerini inceleyebilirsiniz.
Görsel – 1
Görsel – 2
Şimdi örnekler ile anlattıklarımızı uygulayalım
1)Database => Properties => Filegroups => MEMORY OPTIMIZED DATA Sekmesinden FG Oluşturulur
Görsel – 3
Bu işlemi script ile yapmak isterseniz aşağıdaki komutu kullanabilirsiniz.
ALTER DATABASE MuratTest ADD FILEGROUP InMemTest_FG CONTAINS MEMORY_OPTIMIZED_DATA ;
2)Database File’ları içine yeni bir datafile row ekleyip, bu rowu oluşturduğumuz File Gruba atayarak In-Memory Oltp file’i database için oluşmuş olur.
Görsel – 4
ALTER DATABASE MuratTest ADD FILE (NAME=InMemTest_File, FILENAME= D:\Data3\Data \InMemTest_File.mdf') TO FILEGROUP InMemTest_FG;
3)Database için In-memory OLTP aktif edildikten sonra aşağıdaki işlemler ihtiyaca göre yapılır.
CREATE TABLE dbo.TradeOrders ( OrderID BIGINT NOT NULL PRIMARY KEY NONCLUSTERED, TraderID INT NOT NULL, Symbol NVARCHAR(10) NOT NULL, OrderType CHAR(1) NOT NULL, Quantity INT NOT NULL, Price DECIMAL(18,4) NOT NULL, OrderTime DATETIME2 NOT NULL, INDEX IX_OrderTime NONCLUSTERED(OrderTime) ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA); --WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY);
- Oluşturulan tabloda “SCHEMA_AND_DATA” şeklinde oluşturulduğunda veriyi In-Memory tablo içinde tutar fakat Sql Service(Engine) olsa dahi veriye kaybı olmaz.
- Oluşturulan tabloda “SCHEMA_ONLY” şeklinde oluşturulduğunda veriyi In-Memory tablo içinde tutar fakat Sql Service(Engine) restart olduğunda veriye erişim sağlanamaz.
4)Oluşturduğumuz In-Memory tabloya ait bilgileri görmek için aşağıdaki script ile kontrol edebiliriz.
SELECT sfg.name Name, sdf.name logicalFileName, sfg.type_desc, sdf.physical_name FROM sys.filegroups sfg JOIN sys.database_files sdf ON sfg.data_space_id = sdf.data_space_id WHERE sfg.type = 'FX' AND sdf.type = 2
Şimdi In-Memory Table en iyi şekilde faydalanabilmek için native compiled stored procedürler oluşturacağız, bunun içinde yukarıda oluşturduğumuz tabloyu kullanacağız.
CREATE PROCEDURE dbo.PlaceOrder @OrderID BIGINT, @TraderID INT, @Symbol NVARCHAR(10), @OrderType CHAR(1), @Quantity INT, @Price DECIMAL(18,4), @OrderTime DATETIME2 WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english' ) INSERT INTO dbo.TradeOrders (OrderID, TraderID, Symbol, OrderType, Quantity, Price, OrderTime) VALUES (@OrderID, @TraderID, @Symbol, @OrderType, @Quantity, @Price, @OrderTime); END
2014 yılında gelen In-memory Table ve Native Stored Procedures bahsettik, bir sonraki makalede görüşünceye dek iyi ki varsınız, sevgiler 🙂
Kaynak:
https://learn.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/overview-and-usage-scenarios?view=sql-server-ver16
https://learn.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/introduction-to-memory-optimized-tables?view=sql-server-ver16
https://learn.microsoft.com/tr-tr/SQL/relational-databases/in-memory-oltp/sql-server-in-memory-oltp-internals-for-sql-server-2016?view=sql-server-linux-ver16
https://learn.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/overview-and-usage-scenarios?view=sql-server-ver16
0 Yorum