SqlQuantumLeap icon

Jackrabbit OAK-8977 (Improve performance)

SqlQuantumLeap | PRO | 04/07/20 07:15:20 AM UTC | 0 ⭐ | 7865 👁️ | Never ⏰ | []
T-SQL |

11.06 KB

|

None

|

0 👍

/

0 👎

/*******************************************************************
 * Script:  JackRabbitOAK8977.sql ( https://pastebin.com/csh4fy42 )
 * By:      Solomon Rutzky ( https://SqlQuantumLeap.com/ )
 * On:      2020-03-29
 * Issue:   RDBBlobStore performance improvement for SQL Server (MSSQL)
 *          https://issues.apache.org/jira/browse/OAK-8977
 * Purpose: Prove best combination is binary collation and stored proc.
 *******************************************************************/
 
GO
-- https://sqlquantumleap.com/2018/12/28/prevent-full-script-execution-understanding-and-using-parseonly-and-noexec/
SET PARSEONLY ON;
GO
 
-- add RDBBlobStore performance test ( https://issues.apache.org/jira/browse/OAK-8926 )
-- http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBBlobStoreDB.java?revision=1874271&view=markup
 
 
 
--------------------------------------------------------------------------------
--- BEGIN SETUP
--- Highlight down to "END SETUP" and execute
--------------------------------------------------------------------------------
 
 
 
USE [tempdb];
 
---------------------------------------------------------
-- DROP TABLE dbo.[DATASTORE_DATA];
-- DROP TABLE dbo.[DATASTORE_META];
 
CREATE TABLE dbo.[DATASTORE_DATA]
(
    [ID] VARCHAR(64) COLLATE Latin1_General_CI_AS NOT NULL, -- Scenario = 1
    [DATA] VARBINARY(MAX),
    CONSTRAINT [DATASTORE_DATA_PK] PRIMARY KEY CLUSTERED ([ID] ASC)
);
 
CREATE TABLE dbo.[DATASTORE_META]
(
    [ID] VARCHAR(64) COLLATE Latin1_General_CI_AS NOT NULL, -- Scenario = 1
    [LVL] INT,
    [LASTMOD] BIGINT,
    CONSTRAINT [DATASTORE_META_PK] PRIMARY KEY CLUSTERED ([ID] ASC)
);
---------------------------------------------------------
GO
IF (OBJECT_ID(N'dbo.StoreBlockInDatabase') IS NULL)
BEGIN
    EXEC(N'CREATE PROCEDURE dbo.[StoreBlockInDatabase] AS SET NOCOUNT ON;');
END;
 
GO
ALTER PROCEDURE dbo.[StoreBlockInDatabase]
(
    @Digest VARBINARY(32),
    @Level INT,
    @Data VARBINARY(MAX)
)
AS
SET NOCOUNT ON;
 
DECLARE @Id VARCHAR(64) = CONVERT(VARCHAR(64), @Digest, 2),
        @Now BIGINT;
 
SELECT @Now = [cpu_ticks]
FROM   sys.dm_os_sys_info;
 
BEGIN TRY
    UPDATE dbo.[DATASTORE_META]
    SET    [LASTMOD] = @Now
    WHERE  [ID] = @Id;
 
    IF (@@ROWCOUNT = 0)
    BEGIN
        INSERT INTO dbo.[DATASTORE_DATA] ([ID], [DATA]) VALUES (@Id, @Data);
        INSERT INTO dbo.[DATASTORE_META] ([ID], [LVL], [LASTMOD]) VALUES (@Id, @Level, @Now);
    END;
END TRY
BEGIN CATCH
    ;THROW;
END CATCH;
 
GO
---------------------------------------------------------
GO
IF (OBJECT_ID(N'dbo.StoreBlockInDatabase2') IS NULL)
BEGIN
    EXEC(N'CREATE PROCEDURE dbo.[StoreBlockInDatabase2] AS SET NOCOUNT ON;');
END;
 
GO
ALTER PROCEDURE dbo.[StoreBlockInDatabase2]
(
    @Digest VARBINARY(32),
    @Level INT,
    @Data VARBINARY(MAX)
)
AS
SET NOCOUNT ON;
 
DECLARE @Id VARCHAR(64) = CONVERT(VARCHAR(64), @Digest, 2),
        @Now BIGINT;
 
SELECT @Now = [cpu_ticks]
FROM   sys.dm_os_sys_info;
 
BEGIN TRY
    IF (EXISTS(
            SELECT *
            FROM   dbo.[DATASTORE_META]
            WHERE  [ID] = @Id
            ))
    BEGIN
        UPDATE dbo.[DATASTORE_META]
        SET    [LASTMOD] = @Now
        WHERE  [ID] = @Id;
    END;
    ELSE
    BEGIN
        INSERT INTO dbo.[DATASTORE_DATA] ([ID], [DATA]) VALUES (@Id, @Data);
        INSERT INTO dbo.[DATASTORE_META] ([ID], [LVL], [LASTMOD]) VALUES (@Id, @Level, @Now);
    END;
END TRY
BEGIN CATCH
    ;THROW;
END CATCH;
 
GO
---------------------------------------------------------
GO
IF (OBJECT_ID(N'tempdb..#RunTests') IS NULL)
BEGIN
    EXEC(N'CREATE PROCEDURE #RunTests AS SET NOCOUNT ON;');
END;
 
GO
ALTER PROCEDURE #RunTests
(
    @Iterations TINYINT = 10,
    @BlockSize INT = 1500,
    @DurationMS INT = 2000,
    @SingleTestPattern TINYINT = NULL
)
AS
SET NOCOUNT ON;
 
IF (OBJECT_ID(N'dbo.[TestResults]') IS NULL)
BEGIN
    -- DROP TABLE dbo.[TestResults];
    CREATE TABLE dbo.[TestResults]
    (
        [TestResultsID] INT NOT NULL
            IDENTITY(1, 1)
            CONSTRAINT [PK_TestResults] PRIMARY KEY,
        [TestTime] DATETIME2 NOT NULL
            CONSTRAINT [DF_TestResults_TestTime] DEFAULT (SYSDATETIME()),
        [Scenario] TINYINT NOT NULL,
        [TestPattern] TINYINT NOT NULL,
        [RowsInserted] INT NOT NULL,
        [TotalRows] INT NOT NULL
    );
END;
 
 
DECLARE @TestPattern TINYINT = 1;
 
DECLARE @Iteration TINYINT = 0,
        @RowCount INT = 0,
        @EndTime DATETIME2,
        @DATA VARBINARY(MAX),
        @Digest BINARY(32),
        @ID VARCHAR(64),
        @SQL NVARCHAR(MAX),
        @Scenario TINYINT;
 
-- NOTE: Does not yet handle scenario 3!!
SELECT @Scenario = CASE col.[collation_name]
                    WHEN N'Latin1_General_CI_AS' THEN 1
                    WHEN N'Latin1_General_BIN2' THEN 2
                    ELSE 0
                END
FROM  sys.columns col
WHERE col.[object_id] = OBJECT_ID(N'dbo.DATASTORE_META')
AND   col.[name] = N'ID';
 
 
WHILE (@TestPattern < 7)
BEGIN
    SET @Iteration = 0;
 
    -- Execute the following 2 statements when changing either TestPattern or Scenario (for consistency):
    TRUNCATE TABLE dbo.[DATASTORE_DATA];
    TRUNCATE TABLE dbo.[DATASTORE_META];
 
    WHILE (@Iteration < @Iterations)
    BEGIN
        SET @RowCount = 0;
        SET @EndTime = DATEADD(MILLISECOND, @DurationMS, SYSDATETIME());
 
        WHILE (SYSDATETIME() < @EndTime)
        BEGIN
            SET @DATA = CRYPT_GEN_RANDOM(@BlockSize);
 
            SET @Digest = HASHBYTES('SHA2_256', @DATA);
 
            SET @ID = CONVERT(VARCHAR(64), @Digest, 2);
 
 
            BEGIN TRAN; -- I think the JDBC code is doing this
 
            IF (@TestPattern = 1)
            BEGIN
                UPDATE dbo.[DATASTORE_META]
                SET    [LASTMOD] = CONVERT(INT, GETDATE()) -- not a long / ticks, but close enough for this test
                WHERE  [ID] = @ID;
 
                IF (@@ROWCOUNT = 0)
                BEGIN
                    INSERT INTO dbo.[DATASTORE_DATA] ([ID], [DATA]) VALUES (@ID, @DATA);
                    INSERT INTO dbo.[DATASTORE_META] ([ID], [LVL], [LASTMOD]) VALUES (@ID, 0, CONVERT(INT, GETDATE()));
                END;
            END;
 
 
            IF (@TestPattern = 2)
            BEGIN
                IF (EXISTS(
                        SELECT *
                        FROM   dbo.[DATASTORE_META]
                        WHERE  [ID] = @ID
                        ))
                BEGIN
                    UPDATE dbo.[DATASTORE_META]
                    SET    [LASTMOD] = CONVERT(INT, GETDATE()) -- not a long / ticks, but close enough for this test
                    WHERE  [ID] = @ID;
                END;
                ELSE
                BEGIN
                    INSERT INTO dbo.[DATASTORE_DATA] ([ID], [DATA]) VALUES (@ID, @DATA);
                    INSERT INTO dbo.[DATASTORE_META] ([ID], [LVL], [LASTMOD]) VALUES (@ID, 0, CONVERT(INT, GETDATE()));
                END;
            END;
 
 
            IF (@TestPattern = 3)
            BEGIN
                SET @SQL = N'
                UPDATE dbo.[DATASTORE_META]
                SET    [LASTMOD] = CONVERT(INT, GETDATE()) -- not a long / ticks, but close enough for this test
                WHERE  [ID] = ''' + @ID + N''';
 
                IF (@@ROWCOUNT = 0)
                BEGIN
                    INSERT INTO dbo.[DATASTORE_DATA] ([ID], [DATA]) VALUES (''' + @ID + N''', ' + CONVERT(NVARCHAR(MAX), @DATA, 1) + N');
                    INSERT INTO dbo.[DATASTORE_META] ([ID], [LVL], [LASTMOD]) VALUES (''' + @ID + N''', 0, CONVERT(INT, GETDATE()));
                END;
                ';
 
                EXEC(@SQL);
            END;
 
 
            IF (@TestPattern = 4)
            BEGIN
 
                SET @SQL = N'EXEC dbo.[StoreBlockInDatabase] 0x' + @ID + N', 0, ' + CONVERT(NVARCHAR(MAX), @DATA, 1) + N';';
 
                EXEC(@SQL);
            END;
 
 
            IF (@TestPattern = 5)
            BEGIN
                EXEC sp_executesql
                    N'EXEC dbo.[StoreBlockInDatabase] @tmpDigest, 0, @tmpData;',
                    N'@tmpDigest VARBINARY(32), @tmpData VARBINARY(MAX)',
                    @tmpDigest = @Digest,
                    @tmpData = @DATA;
            END;
 
 
            IF (@TestPattern = 6)
            BEGIN
                EXEC sp_executesql
                    N'EXEC dbo.[StoreBlockInDatabase2] @tmpDigest, 0, @tmpData;',
                    N'@tmpDigest VARBINARY(32), @tmpData VARBINARY(MAX)',
                    @tmpDigest = @Digest,
                    @tmpData = @DATA;
            END;
 
 
            COMMIT TRAN; -- I think the JDBC code is doing this
 
            SET @RowCount += 1;
        END;
 
        INSERT INTO dbo.[TestResults] ([Scenario], [TestPattern], [RowsInserted], [TotalRows])
        OUTPUT INSERTED.*
            SELECT @Scenario, @TestPattern, @RowCount, COUNT(*)
            FROM   dbo.[DATASTORE_DATA];
 
        SET @Iteration += 1;
 
        WAITFOR DELAY '00:00:00.500'; -- half-second delay
    END;
 
    SET @TestPattern += 1;
END;
GO
 
--------------------------------------------------------------------------------
--- END SETUP
--------------------------------------------------------------------------------
 
 
-- Exec test proc, apply Scenario 2 changes, then exec test proc again:
 
EXEC #RunTests;
 
 
----------------------------------------
-- Scenario = 2 (change collation to binary)
 
ALTER TABLE [DATASTORE_DATA] DROP CONSTRAINT [DATASTORE_DATA_PK];
ALTER TABLE [DATASTORE_DATA] ALTER COLUMN [ID] VARCHAR(64) COLLATE Latin1_General_BIN2 NOT NULL;
ALTER TABLE [DATASTORE_DATA] ADD CONSTRAINT [DATASTORE_DATA_PK] PRIMARY KEY CLUSTERED ([ID] ASC);
 
ALTER TABLE [DATASTORE_META] DROP CONSTRAINT [DATASTORE_META_PK];
ALTER TABLE [DATASTORE_META] ALTER COLUMN [ID] VARCHAR(64) COLLATE Latin1_General_BIN2 NOT NULL;
ALTER TABLE [DATASTORE_META] ADD CONSTRAINT [DATASTORE_META_PK] PRIMARY KEY CLUSTERED ([ID] ASC);
----------------------------------------
 
EXEC #RunTests;
 
 
 
/* -- Highlight and execute as necessary:
 
SELECT * FROM dbo.[DATASTORE_DATA];
SELECT * FROM dbo.[DATASTORE_META];
 
DELETE FROM dbo.[TestResults] WHERE [TestResultsID] = xyz;
SELECT * FROM dbo.[TestResults];
*/
 
 
 
-- TestPattern 3 = close approximation of current code
-- TestPattern 5 = proposed stored procedure approach
SELECT [Scenario], [TestPattern],
    COUNT([RowsInserted]) AS [TestCount],
    MIN([RowsInserted]) AS [MinRows],
    AVG([RowsInserted]) AS [AvgRows],
    MAX([RowsInserted]) AS [MaxRows],
    SUM([RowsInserted]) AS [TotalRows]
FROM dbo.[TestResults]
GROUP BY [Scenario], [TestPattern]
ORDER BY [Scenario], [TestPattern];
/*
Scenario   TestPattern   TestCount   MinRows   AvgRows   MaxRows   TotalRows
1          1             10          11605     13329     14583     133297
1          2             10          11409     14522     16547     145221
1          3             10           1681      2108      2322      21080
 
2          1             10          12755     16064     17108     160640
2          2             10          13959     15312     16927     153125
2          3             10           2144      2422      2696      24228
2          4             10           2238      3012      3802      30121
2          5             10            963      4876      6626      48768
2          6             10            907      4696      6532      46969
*/
 
 
 
----------------------------------------
-- Scenario = 3 (keep binary collation, change PK to NONclustered)
 
ALTER TABLE [DATASTORE_DATA] DROP CONSTRAINT [DATASTORE_DATA_PK];
ALTER TABLE [DATASTORE_DATA] ALTER COLUMN [ID] VARCHAR(64) COLLATE Latin1_General_BIN2 NOT NULL;
ALTER TABLE [DATASTORE_DATA] ADD CONSTRAINT [DATASTORE_DATA_PK] PRIMARY KEY NONCLUSTERED ([ID] ASC);
 
ALTER TABLE [DATASTORE_META] DROP CONSTRAINT [DATASTORE_META_PK];
ALTER TABLE [DATASTORE_META] ALTER COLUMN [ID] VARCHAR(64) COLLATE Latin1_General_BIN2 NOT NULL;
ALTER TABLE [DATASTORE_META] ADD CONSTRAINT [DATASTORE_META_PK] PRIMARY KEY NONCLUSTERED ([ID] ASC);
----------------------------------------
 
GO
-- https://sqlquantumleap.com/2018/12/28/prevent-full-script-execution-understanding-and-using-parseonly-and-noexec/
SET PARSEONLY OFF;
GO

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎