Archive

Archive for June, 2015

In-Memory OLTP –Part 9

June 22, 2015 Leave a comment

How is my Data written?

 

The data in memory-optimized tables is stored as free-form data rows that are linked through one or more in-memory indexes, in memory. There are no page structures for data rows, such as those used for disk-based tables. When the application is ready to commit the transaction, the In-Memory OLTP generates the log records for the transaction. The persistence of memory-optimized tables is done with a set of data and delta files using a background thread. The data and delta files are located in one or more containers (using the same mechanism used for FILESTREAM data). These containers are mapped to a new type of filegroup, called a memory-optimized filegroup.

Data is written to these files in a strictly sequential fashion, which minimizes disk latency for spinning media. You can use multiple containers on different disks to distribute the I/O activity. Data and delta files in multiple containers on different disks will increase recovery performance when data is read from the data and delta files on disk, into memory.

An application does not directly access data and delta files. All data reads and writes use in-memory data.

 

At this moment I don’t have any pending checkpoints to be written to Data and Delta files , so it is as good as a clean In-Memory Table

Forced checkpoint manually.

image

Lets insert couple of records,900 records inserted

 

image

As we know , system default checkpoint occurs when the log has growth up to 512 MB after the last checkpoint.Let check how much log has been generated from out last insert.

 

image

Since last checkpoint the log has grown less then 1 MB, no checkpoint will occurs as it does not qualify the 512 MB mark.So  the data remains in the log.To check that we will see the use of undocumented function sys.fn_dblog_xtp which is similar to sys.fn_dblog but specifically for In-Memory objects.

 

So, we have done 900 inserts in the table which can been seen in the log.these transactions are still waiting to be written to the DETA File.

 

image

Issues a manual checkpoint to force the log records to flush out and be written on the DETA files.Below are set of events gets captured in the database log,

 

All the log records will be flushed out

image 

Description

XTP chained record ver 3: log_Discriminator = 0x00000001, log_prevRec = 00000000:00000000:0000

XTP chained record ver 3: log_Discriminator = 0x00000003, log_prevRec = 00000000:00000000:0000
XTP complete checkpoint ver 4: { LSN = ;000004f9:00000040:0003;, previous checkpoint completion LSN = ;000004f9:00000068:0003;, close LSN = ;000004f9:000000c8:0005;, CkptTs = 0x0000016d, SerializeTs = 0x0000016f };, { CkptDir ==> GUIDs = { Rowset 83a190b
HkFsStgCreateNewFile;0x01
Operation CREATE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-000000f8-0002
InsertFSV;0x01

Field m_typeFlagBits
Operation CLOSE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-000000f8-0002;CrLSN 000004f9-000000f8-0002;OpLSN 000004f9-00000100-0009;OldFileSz 0;FileSz 0;Off 0;Sz 0;Flg 0007

HkFsStgCreateNewFile;0x01
Operation CREATE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000110-0002
InsertFSV;0x01

Operation CLOSE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000110-0002;CrLSN 000004f9-00000110-0002;OpLSN 000004f9-00000110-0008;OldFileSz 0;FileSz 0;Off 0;Sz 0;Flg 0007

HkFsStgCreateNewFile;0x01
Operation CREATE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000118-0004
InsertFSV;0x01

Operation CLOSE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000118-0004;CrLSN 000004f9-00000118-0004;OpLSN 000004f9-00000118-000a;OldFileSz 0;FileSz 0;Off 0;Sz 0;Flg 0007

HkFsStgCreateNewFile;0x01
Operation CREATE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000120-0002
InsertFSV;0x01

Operation CLOSE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000120-0002;CrLSN 000004f9-00000120-0002;OpLSN 000004f9-00000120-0008;OldFileSz 0;FileSz 0;Off 0;Sz 0;Flg 0007

Action 0 (HOBTCOUNT) on rowset 72057594038321152. Leaf page count: 2, Reserved page count: 4, Used page count: 4
Action 1 (ROWSETCOUNT) on rowset 72057594038321152. Row count: 6.
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 1, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 2, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 3, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 4, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 5, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 6, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 7, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 8, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 9, mod count: 1390
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594038321152. Column Id: 10, mod count: 1390
Action 0 (HOBTCOUNT) on rowset 72057594038386688. Leaf page count: 1, Reserved page count: 2, Used page count: 2
Action 1 (ROWSETCOUNT) on rowset 72057594038386688. Row count: 6.
Action 0 (HOBTCOUNT) on rowset 72057594060144640. Leaf page count: 2, Reserved page count: 3, Used page count: 3
Action 1 (ROWSETCOUNT) on rowset 72057594060144640. Row count: 30.
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594060144640. Column Id: 1, mod count: 478
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594060144640. Column Id: 2, mod count: 702
Action 2 (ROWSETCOLUMNCOUNT) on rowset 72057594060144640. Column Id: 3, mod count: 478
Action 0 (HOBTCOUNT) on rowset 72057594060210176. Leaf page count: 1, Reserved page count: 2, Used page count: 2
Action 1 (ROWSETCOUNT) on rowset 72057594060210176. Row count: 30.

File Id 65537; Old Header Len = 447; New HeaderLen = 447; Old Container Size = 303038464; New Container Size = 338690048

log_minRecoveryLsn 000004f9:00000128:0017;log_replbeginlsn 00000000:00000000:0000;log_replnextlsn 00000000:00000000:0000;log_distbackuplsn 00000000:00000000:0000;log_distlastlsn 00000000:00000000:0000

XTP chained record ver 3: log_Discriminator = 0x00000001, log_prevRec = 00000000:00000000:0000

HkFsStgCreateNewFile;0x01
Operation CREATE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000170-0002
InsertFSV;0x01

XTP chained record ver 3: log_Discriminator = 0x00000000, log_prevRec = 00000000:00000000:0000
XTP chained record ver 3: log_Discriminator = 0x00000003, log_prevRec = 00000000:00000000:0000
XTP complete checkpoint ver 4: { LSN = ;000004f9:000000c8:0003;, previous checkpoint completion LSN = ;000004f9:000000f0:0002;, close LSN = ;000004f9:00000148:0005;, CkptTs = 0x00000173, SerializeTs = 0x00000176 };, { CkptDir ==> GUIDs = { Rowset 83a190b
Operation CLOSE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000170-0002;CrLSN 000004f9-00000170-0002;OpLSN 000004f9-00000178-0006;OldFileSz 0;FileSz 0;Off 0;Sz 0;Flg 0007

HkFsStgCreateNewFile;0x01
Operation CREATE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000188-0002
InsertFSV;0x01

Operation CLOSE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f9-00000188-0002;CrLSN 000004f9-00000188-0002;OpLSN 000004f9-00000188-0008;OldFileSz 0;FileSz 0;Off 0;Sz 0;Flg 0007

HkFsStgDeleteExistingFile;0x

GarbageCollector;0x

HkFsStgDeleteExistingFile;0x

HkFsStgDeleteExistingFile;0x

HkFsStgDeleteExistingFile;0x

HkFsStgDeleteExistingFile;0x

HkFsStgDeleteExistingFile;0x

HkFsStgCleanupStorageTable;0x

Operation DELETE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f7-00000038-0002

Operation DELETE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f7-00000050-0002

Operation DELETE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f8-000001b0-0002

Operation DELETE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f8-000001c8-0002

Operation DELETE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f8-00000100-0003

Operation DELETE;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f8-00000108-0003

GarbageCollector;0x

Operation GARBAGE COLLECTED;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f7-00000210-0002;FileSize 16777216

Operation GARBAGE COLLECTED;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f7-00000218-0002;FileSize 1048576

Operation GARBAGE COLLECTED;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f7-00000350-0002;FileSize 16777216

Operation GARBAGE COLLECTED;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f7-00000360-0002;FileSize 1048576

Operation GARBAGE COLLECTED;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f8-00000070-0002;FileSize 16777216

Operation GARBAGE COLLECTED;File Id 65537;Name 83a190bd-22eb-4014-90f3-119be1bd3aa5\2031cae3-31ca-4826-88b5-8966355c57d400004f8-00000088-0002;FileSize 1048576

Field m_typeFlagBits

 

select * from sys.fn_dblog_xtp(NULL, NULL) where [Transaction ID]='0000:0007ba6e'

image

 

image

Categories: In-MemoryOLTP

In-Memory OLTP –Part 8

June 20, 2015 Leave a comment

 

Where is my data? Cont…

 

So, As we know the data is saved in checkpoint (data)files , In this post we will go over monitoring the checkpoint files and how data is really saved.

The checkpoint files were created at the location which was provided at the time of adding MEMORY_OPTIMIZED DATA file.

 

image

 

Before we start inserting the data, let check if there are active files.

 

select df.name [FileName],df.physical_name,/*cf.checkpoint_file_id,cf.relative_file_path,*/cf.file_type, cf.file_type_desc,/*cf.checkpoint_pair_file_id,*/cf.file_size_in_bytes,cf.file_size_used_in_bytes, cf.inserted_row_count,cf.deleted_row_count,cf.drop_table_deleted_row_count,convert(nvarchar(500), cf.last_checkpoint_recovery_lsn) last_checkpoint_recovery_lsn,cf.tombstone_operation_lsn from sys.dm_db_xtp_checkpoint_files cf join sys.database_files df on cf.container_id=df.file_id and cf.state= 1

image

 

Insert data into In-Memory Table. Query the sys.dm_db_xtp_checkpoint dmv Meta data and it’s Mapping to physical Checkpoint files on the disk:

 

image

Column inserted_row_count,deleted_row_count,drop_table_deleted_row_count are of interest to understand how basically data is inserted or deleted in In-Memory Table

 

inserted_row_count :  No of rows inserted or updated

deleted_row_count : No of rows deleted

drop_table_deleted_row_count :  How many rows were deleted when the In-Memory Table is dropped.

 

I have updated a million rows, Updates are treated as insert.inserted_row_count is updated with the number of records updated.As this is done in a single transaction all the records will be written in a single DATA file  (A data file contains inserted rows while a delta file contains deleted rows. Each data file is pre-allocated to a size of 128 MBs but can get larger if there is a long running transaction or when a manual merge forces the resultant target file to be larger than 128MB.)

 

image

image

image

 

image

Categories: In-MemoryOLTP

In-Memory OLTP –Part 7

June 16, 2015 Leave a comment

Accessing IN-MEMORY OLTP Tables

 

In-Memory OLTP introduces the concept of native compilation. SQL Server can natively compile stored procedures that access memory-optimized tables. SQL Server is also able to natively compile memory-optimized tables. Native compilation allows faster data access and more efficient query execution than interpreted (traditional) Transact-SQL. Native compilation of tables and stored procedures produce DLLs.

Native compilation of memory optimized table types is also supported. For more information, see Memory-Optimized Table Variables.

Native compilation refers to the process of converting programming constructs to native code, consisting of processor instructions without the need for further compilation or interpretation.

In-Memory OLTP compiles memory-optimized tables when they are created, and natively compiled stored procedures when they are loaded to native DLLs. In addition, the DLLs are recompiled after a database or server restart. The information necessary to recreate the DLLs is stored in the database metadata. The DLLs are not part of the database, though they are associated with the database. For example, the DLLs are not included in database backups.

 

--In-Memory OLTP Tables select is_memory_optimized, [object_id] ObjectID from Adventureworks2014.sys.tables where is_memory_optimized !=0 --Compiled DLL of In-Memory Tables-- SELECT name, description,base_address FROM sys.dm_os_loaded_modules WHERE description = 'XTP Native DLL'

image

 

Where is my data?

A memory-optimized file group internally uses filestream files to store inserted and deleted rows for in-memory tables. There are two types of files. A data file contains inserted rows while a delta file contains deleted rows. Each data file is pre-allocated to a size of 128 MBs but can get larger if there is a long running transaction or when a manual merge forces the resultant target file to be larger than 128MB.These files are also called checkpoint files and they come in pairs of DATA and DELTA.

<Use DatabaseName> SELECT * FROM sys.dm_db_xtp_checkpoint_files GO

CPU : 1 socket : 2 core : 4 logical processor (When the database is configured for MEMORY_OPTIMIZED_DATA ,18 checkpoint files were created with pre-allocated to a size of 16 MB)

 

use AdventureWorks2012 go select * from sys.dm_db_xtp_checkpoint_files cf where state=1

image

Checkpoint file and location

 

image

Categories: In-MemoryOLTP

In-Memory OLTP –Part 6

June 14, 2015 Leave a comment

Table Types In-Memory

 

In-Memory table are similar to disk-based tables with few enhancement for In-Memory OLTP tables.To create a memory optimized table you need to add MEMORY_OPTIMIZED=ON clause with durability mode options (SCHEMA_ONLY and SCHEMA_AND_DATA)

The DURABILITY argument is not applicable to table types, which is a type from which table variables or table-valued parameters could be declared. Variables declared using memory-optimized table types are non-durable by definition.

 

INDEXES: You must specify column and table indexes as part of the CREATE TABLE statement. CREATE INDEX and DROP INDEX are not supported for memory-optimized tables.

 

BUCKET_COUNT : Indicates the number of buckets that should be created in the hash index. The maximum value for BUCKET_COUNT in hash indexes is 1,073,741,824. For more information about bucket counts, see Determining the Correct Bucket Count for Hash Indexes.

Bucket_count is a required argument.

 

Memory-optimized tables support hash indexes and memory-optimized nonclustered indexes. A memory-optimized table supports up to eight indexes. Dynamic hashing is not supported. For more information, see Guidelines for Using Indexes on Memory-Optimized Tables.

A nondurable memory-optimized table requires at least one index at the time of creation. A durable memory-optimized table requires a primary key that is used internally as a recovery index. Indexes cannot be added to an existing memory-optimized table.

Any column that is part of a primary key cannot be updated.

 

CREATE TABLE :

USE [AdventureWorks2014]
GO

CREATE TABLE [Sales].[SalesOrderDetail_imoltp](
   [SalesOrderID] [int] NOT NULL,
   [SalesOrderDetailID] [int] IDENTITY(1,1) NOT NULL,
   [CarrierTrackingNumber] [nvarchar](25) NULL,
   [OrderQty] [smallint] NOT NULL,
   [ProductID] [int] NOT NULL,
   [SpecialOfferID] [int] NOT NULL,
   [UnitPrice] [money] NOT NULL,
   [UnitPriceDiscount] [money] NOT NULL CONSTRAINT [DF_SalesOrderDetail_UnitPriceDiscount1]  DEFAULT ((0.0)),
   [ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_SalesOrderDetail_ModifiedDate1]  DEFAULT (getdate()),

   CONSTRAINT [PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID_1] PRIMARY KEY NONCLUSTERED  
   (
      [SalesOrderID] ASC,
      [SalesOrderDetailID] ASC
   ),
   INDEX [PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID_2] NONCLUSTERED HASH ([SalesOrderID],[SalesOrderDetailID]) 
  WITH (BUCKET_COUNT = 1048576),
   INDEX [IX_SalesOrderDetail_ProductId_1] NONCLUSTERED ([ProductId] ASC)
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)

GO

INSERT DATA into Sales.SalesOrderDetail_imoltp

SET IDENTITY_INSERT  Sales.SalesOrderDetail_imoltp ON
insert into Sales.SalesOrderDetail_imoltp 
(
SalesOrderID,SalesOrderDetailID,CarrierTrackingNumber,
OrderQty,ProductID,SpecialOfferID,UnitPrice,UnitPriceDiscount,
ModifiedDate
)
select SalesOrderID,SalesOrderDetailID,CarrierTrackingNumber,
OrderQty,ProductID,SpecialOfferID,UnitPrice,UnitPriceDiscount,ModifiedDate 
from sales.SalesOrderDetail
SET IDENTITY_INSERT  Sales.SalesOrderDetail_imoltp OFF
Categories: In-MemoryOLTP

In-Memory OLTP –Part 5

June 13, 2015 Leave a comment

 

Create In-Memory database or use the exiting database to use In-Memory feature

 

Configure existing database for In-Memory OLTP .Add an In-Memory OLTP file group  and file to an existing database.

  • You do not need to enable filestream to create a memory-optimized filegroup. The mapping to filestream is done by the In-Memory OLTP engine.

 

Limitations of memory-optimized filegroup,

  • Once you create a memory-optimized filegroup, you can only remove it by dropping the database. In a production environment, it is unlikely that you will need to remove the memory-optimized filegroup.

  • You cannot drop a non-empty container or move data and delta file pairs to another container in the memory-optimized filegroup.

  • You cannot specify MAXSIZE for the container.

 

ALTER DATABASE AdventureWorks2014
ADD FILEGROUP INMOLTP_fg CONTAINS MEMORY_OPTIMIZED_DATA;
GO

ALTER DATABASE AdventureWorks2014
ADD FILE (NAME='INMOLTP_fg', FILENAME='C:\SQLDatabase\DB\INMemory_OLTP\INMOLTP_fg')
  TO FILEGROUP INMOLTP_fg;
GO

 

Database In-Memory OLTP Status

 

SELECT   CASE  
	WHEN SERVERPROPERTY('IsXTPSupported')= 1 THEN ' Server supports In-Memory OLTP.'  
	WHEN SERVERPROPERTY('IsXTPSupported')= 0 THEN 'Server does not supports In-Memory OLTP.' 
	ELSE 'Input is not valid, an error, or not applicable.' END

 

image

 

Query Database file status

 

select s.name,g.name,g.type,g.type_desc,s.type,s.type_desc,s.physical_name,s.state_desc from 
sys.filegroups AS g
INNER JOIN sys.database_files AS s ON ((s.type = 2 or s.type = 0) 
and (s.drop_lsn IS NULL)) AND (s.data_space_id=g.data_space_id)

 

image 

 

Note: Optimized file group can be deleted if there is no Optimized file is associated to it. As you create the memory optimized file SQL Server will assign memory to it and system memory objects.

 

use AdventureWorks2014
go
select * from sys.dm_xtp_system_memory_consumers

 

image

Memory Optimized filegroup stores memory optimized data in the file system

 

image

 

Check the database-level memory consumers in the In-Memory OLTP database engine. The view returns a row for each memory consumer that the database engine uses.

select * from sys.dm_db_xtp_memory_consumers

image

 

Initial memory utilization : In-Memory Configuration

select  convert(char(10), object_name(object_id)) as Name, 
convert(char(10),memory_consumer_type_desc ) as memory_consumer_type_desc, 
object_id,index_id, allocated_bytes,  used_bytes 
from sys.dm_db_xtp_memory_consumers

 

image

Categories: In-MemoryOLTP

SQL Server Server Property

June 10, 2015 Leave a comment

 

SELECT SERVERPROPERTY(‘productversion’), SERVERPROPERTY(‘productlevel’), SERVERPROPERTY(‘edition’)

 

image

Categories: T-SQL-Scripts

Robocopy : Copy files

June 10, 2015 Leave a comment

Copy all files from the Source Folder

PS C:\> robocopy Source Destination
——————————————————————————-
   ROBOCOPY     ::     Robust File Copy for Windows
——————————————————————————-

Started : Tuesday, June 9, 2015 9:08:16 AM
Source : \\ServerName\z$\Backup\FULL\
Dest : G:\BACKUPS\VOL01\Restore\
Files : *.*
Options : *.* /DCOPY:DA /COPY:DAT /R:1000000 /W:30

Copy all files from the Source Folder excluding files

PS C:\> Robocopy.exe \\ServerName\z$\Backup\DIFF G:\BACKUPS\VOL01\Restore /XF Filename_20150608_200017*.*

——————————————————————————-
   ROBOCOPY     ::     Robust File Copy for Windows
——————————————————————————-

Started : Wednesday, June 10, 2015 3:11:33 AM
Source : \\ServerName\z$\Backup\DIFF\
Dest : G:\BACKUPS\VOL01\Restore\
Files : *.*
Exc Files : Filename_20150608_200017*.*

Options : *.* /DCOPY:DA /COPY:DAT /R:1000000 /W:30

Categories: T-SQL-Scripts