在SQL server management studio中循环SQL脚本会导致内存泄漏。脚本性能也可以更好
我正在运行以下结构的数据生成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
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来解决内存泄漏问题,这样“消息”选项卡不会被填满。也许你们有更简单的解决方案,像这样?