在SQL server management studio中循环SQL脚本会导致内存泄漏。脚本性能也可以更好

在SQL server management studio中循环SQL脚本会导致内存泄漏。脚本性能也可以更好,sql,sql-server,performance,memory-leaks,Sql,Sql Server,Performance,Memory Leaks,我正在运行以下结构的数据生成SQL脚本: CREATE table T where time it took for each transaction will be stored DECLARE statements SET statements WHILE (condition that will loop for very long time) DECLARE CURSOR and OPEN it WHILE @@FETCH_STATUS = 0 some i

我正在运行以下结构的数据生成SQL脚本:

CREATE table T where time it took for each transaction will be stored

DECLARE statements
SET statements 

WHILE (condition that will loop for very long time)
  DECLARE CURSOR and OPEN it
    WHILE @@FETCH_STATUS = 0
      some if's, some for's, some SET statements for some variables (setting some values depending on the cursor value).
    FETCH NEXT
  CURSOR closing
  SET other variables to random values

  SET @start = SYSDATETIME();
  EXEC [dbo].[UP_XXX]
  SET @end = SYSDATETIME();

  INSERT results into T
END WHILE
但是,这会缓慢地填充数据库-1 mln。每10小时调用一次存储过程(i)+它会导致内存泄漏(我的SSM和SQL server都会占用更多内存)(ii)

我想:

  • 优化脚本以提高速度(对SQL脚本优化有何建议?)
  • 修复内存泄漏-也许一些命令行选项会对每个循环上创建的变量进行垃圾收集?我可以手动操作吗
剧本:

     /*CONSTRUCT TABLE FOR THE PERFORMANCE RESULTS TO BE STORED AT*/
     CREATE TABLE dbo.Performance_Results
     (
            TransactionNumber int NOT NULL PRIMARY KEY IDENTITY(1,1),
            TimeTaken_mcs int,
            TimeTaken_ms int,
            TimeTaken_s int,
            InputStringLength int,
            InputString varchar(5000),
            InfoOut varchar(4096)
     );

     /*
     PERFORMANCE testing AND DATA GENERATION SCRIPT
     ATTENTION: script uses @counter and @maxcounter variables for how many times it will run, please adjust them
     */

     USE [my_DB] 
     GO

     Declare    @counter int, /*<< for the loop*/
            @maxcounter int,

            @TypeId int, /*<< for CURSOR solution*/
            @Type varchar(32),
            @inputStr varchar(2048),

            @TypeToVarBinary VARBINARY(MAX),    
            @bankdetails VARCHAR(MAX),
            @cardnumber VARCHAR(MAX),
            @dateofbirth VARCHAR(MAX),
            @domid VARCHAR(MAX),
            @emailaddress VARCHAR(MAX),
            @IPaddress VARCHAR(MAX),
            @resid VARCHAR(MAX),
            @telephone VARCHAR(MAX),

            @acc_number varchar (10), /*<< for the non hashed string inputs (one fore each  type)*/
            @sortCode varchar (10),
            @bankdetails varchar(MAX),

            @cardnumber varchar(20),
            @dateofbirth varchar(10),
            @domid varchar(10),
            @emailaddress varchar(70),
            @resid varchar(10),
            @telephone varchar(11),

            @Types varchar(20),/*for @inputString*/
            @ValidCharacters varchar(20),
            @HashCharacters varchar(70),
            @email varchar(40),
            @IPaddress varchar (40),
            @DataLength smallint,

            @concatenatedStringPart1 int, /*for LTJ*/
             @concatenatedStringPart2 int, 
             @concatenatedStringPart3 int, 
             @concatenatedStringPart4 int,

            @inputString varchar (2048), /*<< INPUTS for stored procedure*/
            @ltjInput varchar(60),
            @sectorIdInput bigint,
            @companyIdInput bigint,
            @groupIdInput bigint,
            @profileIdInput bigint,

            @idOut bigint, /*<< OUTPUTS OF stored procedure*/
            @inputsSuppliedOut int,
            @inputsOkOut int,
            @infoOut varchar(4096),

            @start Datetime2,/*datetime2 has more precision than datetime :: datetime2 is accurate to 100ns, datetime only goes in incremens: 200, 500, 700*/
            @end Datetime2

     /*setting variables which will not change as the loop iterates*/       
     SET        @ValidCharacters = 'abcdefghijklmnopqrstuvwxy'
     SET        @DataLength = DATALENGTH (@ValidCharacters) - 1;

     /*setting variables for the out-most loop*/        
     SET        @maxcounter = 10000000;
     SET        @counter = 0;


     WHILE  @counter <= @maxcounter

        BEGIN
            /***************************************** SOLUTION WITH CURSORS ********************************************/
            SET     @inputString = '';

            DECLARE cursor_types CURSOR FOR
            SELECT TOP ((ABS(CHECKSUM(NewId())) % 8) + 1) * FROM type ORDER BY NEWID() --ordering randomly, then selecting random number of elements
            OPEN cursor_types

            FETCH NEXT FROM cursor_types
            INTO @TypeId, @yType

            WHILE @@FETCH_STATUS = 0
                BEGIN
                    IF (@inputString != '')
                        SET @inputString = @inputString + '|';

                        /**THIS WHERE I CONSTRUCT THE INPUT STRING**/

                            /**CASES FOR EACH TYPE**/

                            IF (@Type = 'bankdetails')
                                BEGIN
                                    SET @sortCode = CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 900000 + 100000 AS VARCHAR)
                                    SET @acc_number = CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 900000000 + 10000000 AS VARCHAR)
                                    SET @bankdetails = @sortCode + ' ' + @acc_number

                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @bankdetails)
                                    SET @bankdetails = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @bankdetails;
                                END

                            ELSE IF (@Type = 'cardnumber')
                                BEGIN
                                    /*cardnumber - 341614349755260 [12-19] numbers*/
                                    SET @cardnumber = CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS BIGINT)) AS VARCHAR) --19 diggits
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @cardnumber)
                                    SET @cardnumber = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @cardnumber;
                                END

                            ELSE IF (@Type = 'dateofbirth')
                                BEGIN
                                    /*dateofbirth - 15/01/1981, pattern :: [dd] + '/' + [dd] + '/' [dddd]*/
                                    SET @dateofbirth = (CAST(CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) % 30 + 1 AS varchar) + --days
                                                 '/' + CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) % 12 + 1 AS varchar) + --months
                                                 '/' + CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) % 109 + 1900 AS varchar) AS VARCHAR)) --years
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @dateofbirth)
                                    SET @dateofbirth = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @dateofbirth;
                                END

                            ELSE IF (@Type = 'domid')
                                BEGIN
                                    /*domid - from CR, pattern :: 36614147*/
                                    SET @domid = (CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 90000000 + 10000000 AS VARCHAR))
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @domid)
                                    SET @domid = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @domid;
                                END

                            ELSE IF (@Type = 'emailaddress')
                                BEGIN
                                    /*emailaddress :: uses the variable @ValidCharacters to construct random lenght email addy*/
                                    SET @emailaddress = SUBSTRING(@ValidCharacters,ABS(CHECKSUM(NewId())) % @DataLength + 1,ABS(CHECKSUM(NewId())) % @DataLength + 1) + 
                                            '@' + SUBSTRING(@ValidCharacters,ABS(CHECKSUM(NewId())) % @DataLength + 1, ABS(CHECKSUM(NewId())) % @DataLength + 1) + '.com'       
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @emailaddress)
                                    SET @emailaddress = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @emailaddress;
                                END

                            ELSE IF (@Type = 'ipaddress')
                                BEGIN
                                    /*ipaddress - >> [0-255].[0-255].[0-255].[0-255] -- tiny int is 1 byte so 0-255*/
                                    SET @IPaddress = CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) AS varchar)  + '.' 
                                                    + CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) AS varchar) + '.' 
                                                    + CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) AS varchar) + '.'
                                                    + CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS tinyint)) AS varchar)
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @IPaddress)
                                    SET @IPaddress = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @IPaddress;
                                END

                            ELSE IF (@Type = 'resid')
                                BEGIN
                                    /*resid - from CR, the pattern :: 237637668 */
                                    SET @resid = CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 900000000 + 100000000 AS VARCHAR)
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @resid)
                                    SET @resid = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @resid;
                                END

                            ELSE IF (@Type = 'telephone')
                                BEGIN
                                    /*telephone - 11 diggits all striped :: can implement the 9-11 diggits*/
                                    SET @telephone = CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS BIGINT) / 100000000 ) AS varchar);
                                    SET @TypeToVarBinary = CONVERT(varbinary(max), @telephone)
                                    SET @telephone = CAST(CAST('' as XML).value('xs:base64Binary(sql:variable("@TypeToVarBinary"))', 'varchar(max)') as varchar(MAX))
                                    SET @inputString = @inputString + @Type + '^' + @telephone;
                                END

                    FETCH NEXT FROM cursor_types
                    INTO @TypeId, @Type

                END

            CLOSE cursor_types
            DEALLOCATE cursor_types 

            /**************************************** END SOLUTION WITH CURSORS ********************************************************/

            SET     @concatenatedStringPart1 = 1000 + ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 9000 /*for LTJ*/
            SET     @concatenatedStringPart2 = 10000 + ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 90000
            SET     @concatenatedStringPart3 = 10000 + ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 90000
            SET     @concatenatedStringPart4 = 1 + ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 9

            SET     @ltjInput = 'LTJ-' + 'OLI' + '-' + CAST(@concatenatedStringPart1 AS varchar(20)) + '-' + CAST(@concatenatedStringPart2 AS varchar(20)) + '-' + CAST(@concatenatedStringPart3 AS varchar(20)) + '-' + CAST(@concatenatedStringPart4 AS VARCHAR) /*the 2nd part - does not change*/
            SET     @sectorIdInput = ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 21; /*1-21*/
            SET     @companyIdInput = ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 1000/*1-1000 :: decided arbitrarilly*/
            SET     @groupIdInput = ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 1000; /*1-1000 :: decided arbitrarilly*/
            SET     @profileIdInput = ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) % 1000 /*1-1000 :: decided arbitrarilly*/

            /*DBCC statements :: act as Database Console Commands for SQL Server.*/
            DBCC    FREEPROCCACHE; -- Removes all elements from the plan cache, a specific plan from the plan cache by specifying a plan handle or SQL handle, or removes all cache entries associated with a specified resource pool.
            DBCC    DROPCLEANBUFFERS; -- Removes all clean buffers from the buffer pool.

            SET     @start = SYSDATETIME();

                    EXEC    [dbo].[UP_XXX]
                        @inputStr = @inputString, 
                        @ltjIn = @ltjInput, 
                        @sectorIdIn = @sectorIdInput, 
                        @companyIdIn = @companyIdInput, 
                        @groupIdIn = @groupIdInput, 
                        @profileIdIn = @profileIdInput, 
                        @idOut = @idOut OUTPUT,
                        @inputsSuppliedOut = @inputsSuppliedOut OUTPUT,
                        @inputsOkOut = @inputsOkOut OUTPUT,
                        @infoOut = @infoOut OUTPUT 

                        -- Display Stored Procedures errors :: SELECT @infoOut;

            SET     @end = SYSDATETIME()
            SET     @counter = @counter + 1

            /*INSERTING THE PERFORMANCE RESULTS INTO THE TABLE*/
            INSERT INTO dbo.Performance_Results VALUES
            (
                DATEDIFF(mcs, @start, @end),
                DATEDIFF(ms, @start, @end),
                DATEDIFF(s, @start, @end),
                LEN(@inputString),
                @inputString,
                @infoOut
            );

        END
/*为要存储在的性能结果构造表*/
创建表dbo.Performance\u结果
(
TransactionNumber int非空主键标识(1,1),
所用时间,
所用时间_msint,
所用时间,
InputStringLength int,
输入字符串varchar(5000),
InfoOut varchar(4096)
);
/*
性能测试和数据生成脚本
注意:脚本将使用@counter和@maxcounter变量运行多少次,请调整它们
*/
使用[我的数据库]
去

声明@counter int,/*为什么不去掉光标?仔细看一下,我不明白为什么这一定是一个光标。以下是让您朝着正确方向前进的起点:

DECLARE @inputString varchar (2048)

SET @inputString = ''

SELECT TOP ((ABS(CHECKSUM(NewId())) % 8) + 1) 
    @inputString = @inputString + '|' + 
    CASE WHEN Type = 'bankdetails' THEN
            bd_bankdetails2.bankdetails2
        WHEN Type = 'cardnumber' THEN
            ...
FROM type 
    CROSS APPLY (SELECT CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 900000 + 100000 AS VARCHAR) sortCode) as bd_SortCode 
    CROSS APPLY (SELECT CAST(ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 900000000 + 10000000 AS VARCHAR) acc_number ) as bd_acc_number  
    CROSS APPLY (SELECT bd_SortCode.sortCode + ' ' + bd_acc_number.acc_number bankdetails1 ) as bd_bankdetails1 
    --CROSS APPLY (SELECT CONVERT(varbinary(max), bd_bankdetails1.bankdetails1) TypeToVarBinary) as bd_TypeToVarBinary 
    CROSS APPLY (SELECT CAST(CAST('' as XML).value(bd_bankdetails1.bankdetails1, 'varchar(max)') as varchar(MAX)) bankdetails2) as bd_bankdetails2
ORDER BY NEWID()

在本例中,我使用交叉应用程序主要是为了显示当前变量的细分情况,这样对您来说会更有意义,但大多数情况下都可以在一个大案例语句中完成。

我尝试关闭任何I/O操作。我设置:“SETNOCOUNT ON”-也许我不应该从SSMS执行查询,而是从SSQL CMD执行查询?我应该如何关闭DDMS到控制台的日志记录?DBCC TRACEOFF(?)没有任何信息——我应该向TRACEOFF的参数添加什么?谢谢你的回答:)我必须检查解决方案才能接受它。[…]我使用游标是因为我需要一组东西来构建一个长字符串的键值/键值-这将有一个随机数目的键值对(为了使它真实(它将如何在生产中)。[…]此外,我还通过(I)使用SET NOCOUNT ON和(ii)使用DBCC而不使用任何infomsg来解决内存泄漏问题,这样“消息”选项卡不会被填满。也许你们有更简单的解决方案,像这样?