Skip to content

Commit 93874c1

Browse files
committed
Example for In-Memory db/table.
1 parent f56b1fb commit 93874c1

File tree

10 files changed

+142
-0
lines changed

10 files changed

+142
-0
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@
55
* Misc index enhancements or testing. Fixes #570
66
Enable `supports_index_sort_order?`, test `supports_partial_index?`, test how expression indexes work.
77

8+
#### Added
9+
10+
* New `primary_key_nonclustered` type for easy In-Memory table creation.
11+
* Examples for an In-Memory table.
12+
13+
```ruby
14+
create_table :in_memory_table, id: false,
15+
options: 'WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)' do |t|
16+
t.primary_key_nonclustered :id
17+
t.string :name
18+
t.timestamps
19+
end
20+
```
21+
822

923
## v5.0.5
1024

lib/active_record/connection_adapters/sqlserver/schema_statements.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ def change_column_null(table_name, column_name, allow_null, default = nil)
253253
def initialize_native_database_types
254254
{
255255
primary_key: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY',
256+
primary_key_nonclustered: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED',
256257
integer: { name: 'int', limit: 4 },
257258
bigint: { name: 'bigint' },
258259
boolean: { name: 'bit' },

lib/active_record/connection_adapters/sqlserver/table_definition.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ def primary_key(name, type = :primary_key, **options)
1111
column name, type, options
1212
end
1313

14+
def primary_key_nonclustered(*args, **options)
15+
args.each { |name| column(name, :primary_key_nonclustered, options) }
16+
end
17+
1418
def real(*args, **options)
1519
args.each { |name| column(name, :real, options) }
1620
end

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ def supports_comments_in_create?
141141
false
142142
end
143143

144+
def supports_in_memory_oltp?
145+
@version_year >= 2014
146+
end
147+
144148
def disable_referential_integrity
145149
tables = tables_with_referential_integrity
146150
tables.each { |t| do_execute "ALTER TABLE #{t} NOCHECK CONSTRAINT ALL" }
@@ -416,6 +420,7 @@ def initialize_dateformatter
416420

417421
def version_year
418422
vstring = _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
423+
return 2016 if vstring =~ /vNext/
419424
/SQL Server (\d+)/.match(vstring).to_a.last.to_s.to_i
420425
rescue Exception => e
421426
2016

test/cases/adapter_test_sqlserver.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,5 +416,14 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
416416

417417
end
418418

419+
it 'in_memory_oltp' do
420+
if ENV['IN_MEMORY_OLTP'] && connection.supports_in_memory_oltp?
421+
SSTMemory.primary_key.must_equal 'id'
422+
SSTMemory.columns_hash['id'].must_be :is_identity?
423+
else
424+
skip 'supports_in_memory_oltp? => false'
425+
end
426+
end
427+
419428
end
420429

test/cases/helper_sqlserver.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Bundler.require :default, :development
44
require 'pry'
55
require 'support/minitest_sqlserver'
6+
require 'support/test_in_memory_oltp'
67
require 'cases/helper'
78
require 'support/load_schema_sqlserver'
89
require 'support/coerceable_test_sqlserver'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class SSTMemory < ActiveRecord::Base
2+
self.table_name = 'sst_memory'
3+
end
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
-- https://msdn.microsoft.com/en-us/library/mt694156.aspx
2+
-- https://raw.githubusercontent.com/Microsoft/sql-server-samples/master/samples/features/in-memory/t-sql-scripts/enable-in-memory-oltp.sql
3+
--
4+
-- The below scipt enables the use of In-Memory OLTP in the current database,
5+
-- provided it is supported in the edition / pricing tier of the database.
6+
-- It does the following:
7+
-- 1. Validate that In-Memory OLTP is supported.
8+
-- 2. In SQL Server, it will add a MEMORY_OPTIMIZED_DATA filegroup to the database
9+
-- and create a container within the filegroup in the default data folder.
10+
-- 3. Change the database compatibility level to 130 (needed for parallel queries
11+
-- and auto-update of statistics).
12+
-- 4. Enables the database option MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT to avoid the
13+
-- need to use the WITH (SNAPSHOT) hint for ad hoc queries accessing memory-optimized
14+
-- tables.
15+
--
16+
-- Applies To: SQL Server 2016 (or higher); Azure SQL Database
17+
-- Author: Jos de Bruijn (Microsoft)
18+
-- Last Updated: 2016-05-02
19+
20+
SET NOCOUNT ON;
21+
SET XACT_ABORT ON;
22+
23+
-- 1. validate that In-Memory OLTP is supported
24+
IF SERVERPROPERTY(N'IsXTPSupported') = 0
25+
BEGIN
26+
PRINT N'Error: In-Memory OLTP is not supported for this server edition or database pricing tier.';
27+
END
28+
IF DB_ID() < 5
29+
BEGIN
30+
PRINT N'Error: In-Memory OLTP is not supported in system databases. Connect to a user database.';
31+
END
32+
ELSE
33+
BEGIN
34+
BEGIN TRY;
35+
-- 2. add MEMORY_OPTIMIZED_DATA filegroup when not using Azure SQL DB
36+
IF SERVERPROPERTY('EngineEdition') != 5
37+
BEGIN
38+
DECLARE @SQLDataFolder nvarchar(max) = cast(SERVERPROPERTY('InstanceDefaultDataPath') as nvarchar(max))
39+
DECLARE @MODName nvarchar(max) = DB_NAME() + N'_mod';
40+
DECLARE @MemoryOptimizedFilegroupFolder nvarchar(max) = @SQLDataFolder + @MODName;
41+
42+
DECLARE @SQL nvarchar(max) = N'';
43+
44+
-- add filegroup
45+
IF NOT EXISTS (SELECT 1 FROM sys.filegroups WHERE type = N'FX')
46+
BEGIN
47+
SET @SQL = N'
48+
ALTER DATABASE CURRENT
49+
ADD FILEGROUP ' + QUOTENAME(@MODName) + N' CONTAINS MEMORY_OPTIMIZED_DATA;';
50+
EXECUTE (@SQL);
51+
52+
END;
53+
54+
-- add container in the filegroup
55+
IF NOT EXISTS (SELECT * FROM sys.database_files WHERE data_space_id IN (SELECT data_space_id FROM sys.filegroups WHERE type = N'FX'))
56+
BEGIN
57+
SET @SQL = N'
58+
ALTER DATABASE CURRENT
59+
ADD FILE (name = N''' + @MODName + ''', filename = '''
60+
+ @MemoryOptimizedFilegroupFolder + N''')
61+
TO FILEGROUP ' + QUOTENAME(@MODName);
62+
EXECUTE (@SQL);
63+
END
64+
END
65+
66+
-- 3. set compat level to 130 if it is lower
67+
IF (SELECT compatibility_level FROM sys.databases WHERE database_id=DB_ID()) < 130
68+
ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 130
69+
70+
-- 4. enable MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT for the database
71+
ALTER DATABASE CURRENT SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = ON;
72+
73+
74+
END TRY
75+
BEGIN CATCH
76+
PRINT N'Error enabling In-Memory OLTP';
77+
IF XACT_STATE() != 0
78+
ROLLBACK;
79+
THROW;
80+
END CATCH;
81+
END;

test/schema/sqlserver_specific_schema.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@
3737

3838
# Edge Cases
3939

40+
if ENV['IN_MEMORY_OLTP'] && supports_in_memory_oltp?
41+
create_table 'sst_memory', force: true, id: false,
42+
options: 'WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)' do |t|
43+
t.primary_key_nonclustered :id
44+
t.string :name
45+
t.timestamps
46+
end
47+
end
48+
4049
create_table 'sst_bookings', force: true do |t|
4150
t.string :name
4251
t.datetime2 :created_at, null: false
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
if ENV['IN_MEMORY_OLTP']
2+
require 'config'
3+
require 'active_record'
4+
require 'support/config'
5+
require 'support/connection'
6+
7+
ARTest.connect
8+
9+
if ActiveRecord::Base.connection.supports_in_memory_oltp?
10+
puts 'Configuring In-Memory OLTP...'
11+
inmem_file = ARTest::SQLServer.test_root_sqlserver, 'schema', 'enable-in-memory-oltp.sql'
12+
inmem_sql = File.read File.join(inmem_file)
13+
ActiveRecord::Base.connection.execute(inmem_sql)
14+
end
15+
end

0 commit comments

Comments
 (0)