SQL Server 2008的鏈接服務器和特設的INSERT引起快速內存泄漏,最終導致服務器無響應,並與下面的錯誤結束系統內存不足:有一個在資源池「內部」
Msg 701, Level 17, State 123, Server BRECK-PC\SQLEXPRESS, Line 2
There is insufficient system memory in resource pool 'internal' to run this
query.
Location: qxcntxt.cpp:1052
Expression: cref == 0
SPID: 51
Process ID: 1880
在SQL Server重新啓動之前,服務器保持不響應狀態。
軟件使用:
Windows Vista旗艦版的64位版本6001 SP1
的Microsoft SQL Server 2008(SP1) - 10.0.2734.0(X64)2009年9月11日14時30分58秒版權所有(c)在Windows NT 6.0 1988-2008微軟公司Express Edition與高級服務(64位)(建設6001:Service Pack 1的)
SAOLEDB.11從SQL Anywhere的驅動11.0.1.2276
將最大服務器內存(MB)設置爲2048並沒有幫助。
將各種-g值(例如-g256;)添加到服務器啓動參數沒有幫助。
使用DBCC FREESYSTEMCACHE('ALL'),DBCC FREESESSIONCACHE和DBCC FREEPROCCACHE沒有幫助。
即使它包含對涉及鏈接服務器使用情況的內存泄漏症狀的修復,也無濟於事,將SQL Server 2008 Service Pack 1的排列更新程序包4安裝不起作用。
分隔SELECT ... ROW_NUMBER()OVER ... INSERT中的查詢沒有幫助。實驗表明,複雜的SELECT不會導致內存泄漏,INSERT也會這樣做。
更改代碼以使用臨時「INSERT INTO OPENROWSET」語法而不是鏈接服務器沒有幫助;以下代碼顯示了鏈接的服務器使用情況。
sysinternals.com進程瀏覽實用程序顯示內存使用量與sqlserver.exe相關,而不是SQL Anywhere OLEDB驅動程序SAOLEDB.11使用的DLL。
請注意,SQL Anywhere版本的鏈接服務器(代理表)工作正常,可在單個事務中將SQL Server 2008表中的190萬行「拉」到SQL Anywhere 11數據庫。這裏顯示的邏輯是嘗試使用鏈接服務器功能來「推」行;相同的方向,不同的語法。
代碼如下;內存4G是後EXECUTE copy_mss_t2三個或四個執行耗盡:
EXEC sys.sp_configure
N'show advanced options',
N'1'
GO
RECONFIGURE WITH OVERRIDE
GO
EXEC sys.sp_configure
N'max server memory (MB)',
N'2048'
GO
RECONFIGURE WITH OVERRIDE
GO
EXEC sys.sp_configure
N'show advanced options',
N'0'
GO
RECONFIGURE WITH OVERRIDE
GO
EXEC master.dbo.sp_MSset_oledb_prop
N'SAOLEDB.11',
N'AllowInProcess',
1
GO
sp_addlinkedserver
@server = 'mem',
@srvproduct = 'SQL Anywhere OLE DB Provider',
@provider = 'SAOLEDB.11',
@datasrc = 'mem_PAVILION2'
GO
EXEC master.dbo.sp_serveroption
@server=N'mem',
@optname=N'rpc',
@optvalue=N'true'
GO
EXEC master.dbo.sp_serveroption
@server=N'mem',
@optname=N'rpc out',
@optvalue=N'true'
GO
sp_addlinkedsrvlogin
@rmtsrvname = 'mem',
@useself = 'false',
@locallogin = NULL,
@rmtuser = 'dba',
@rmtpassword = 'sql'
GO
CREATE PROCEDURE copy_mss_t2
@from_row BIGINT,
@to_row BIGINT,
@rows_copied_count BIGINT OUTPUT
AS
SELECT *
INTO #t
FROM (SELECT *,
ROW_NUMBER()
OVER (ORDER BY sample_set_number,
connection_number)
AS t2_row_number
FROM mss_t2) AS ordered_mss_t2
WHERE ordered_mss_t2.t2_row_number BETWEEN @from_row AND @to_row;
SELECT @rows_copied_count = COUNT(*)
FROM #t;
INSERT INTO mem..dba.sa_t2
SELECT sampling_id,
sample_set_number,
connection_number,
blocker_owner_table_name,
blocker_lock_type,
blocker_owner_name,
blocker_table_name,
blocker_reason,
blocker_row_identifier,
current_engine_version,
page_size,
ApproximateCPUTime,
BlockedOn,
BytesReceived,
BytesSent,
CacheHits,
CacheRead,
"Commit",
DiskRead,
DiskWrite,
FullCompare,
IndAdd,
IndLookup,
Isolation_level,
LastReqTime,
LastStatement,
LockCount,
LockName,
LockTableOID,
LoginTime,
LogWrite,
Name,
NodeAddress,
Prepares,
PrepStmt,
QueryLowMemoryStrategy,
QueryOptimized,
QueryReused,
ReqCountActive,
ReqCountBlockContention,
ReqCountBlockIO,
ReqCountBlockLock,
ReqCountUnscheduled,
ReqStatus,
ReqTimeActive,
ReqTimeBlockContention,
ReqTimeBlockIO,
ReqTimeBlockLock,
ReqTimeUnscheduled,
ReqType,
RequestsReceived,
Rlbk,
RollbackLogPages,
TempFilePages,
TransactionStartTime,
UncommitOp,
Userid,
previous_ApproximateCPUTime,
interval_ApproximateCPUTime,
previous_Commit,
interval_Commit,
previous_Rlbk,
interval_Rlbk
FROM #t;
GO
DECLARE @rows_copied_count BIGINT
EXECUTE copy_mss_t2 1110001, 1120000, @rows_copied_count OUTPUT
SELECT @rows_copied_count
GO
EXECUTE create_linked_server
GO
DECLARE @rows_copied_count BIGINT
EXECUTE copy_mss_t2 1120001, 1130000, @rows_copied_count OUTPUT
SELECT @rows_copied_count
GO
EXECUTE create_linked_server
GO
這裏是SQL Server源表,包含有關數據的1G的190萬行:
CREATE TABLE mss_t2 (
sampling_id BIGINT NOT NULL,
sample_set_number BIGINT NOT NULL,
connection_number BIGINT NOT NULL,
blocker_owner_table_name VARCHAR (257) NULL,
blocker_lock_type VARCHAR (32) NULL,
blocker_owner_name VARCHAR (128) NULL,
blocker_table_name VARCHAR (128) NULL,
blocker_reason TEXT NULL,
blocker_row_identifier VARCHAR (32) NULL,
current_engine_version TEXT NOT NULL,
page_size INTEGER NOT NULL,
ApproximateCPUTime DECIMAL (30, 6) NULL,
BlockedOn BIGINT NULL,
BytesReceived BIGINT NULL,
BytesSent BIGINT NULL,
CacheHits BIGINT NULL,
CacheRead BIGINT NULL,
"Commit" BIGINT NULL,
DiskRead BIGINT NULL,
DiskWrite BIGINT NULL,
FullCompare BIGINT NULL,
IndAdd BIGINT NULL,
IndLookup BIGINT NULL,
Isolation_level BIGINT NULL,
LastReqTime TEXT NOT NULL DEFAULT '1900-01-01',
LastStatement TEXT NULL,
LockCount BIGINT NULL,
LockName BIGINT NULL,
LockTableOID BIGINT NULL,
LoginTime TEXT NOT NULL DEFAULT '1900-01-01',
LogWrite BIGINT NULL,
Name VARCHAR (128) NULL,
NodeAddress TEXT NULL,
Prepares BIGINT NULL,
PrepStmt BIGINT NULL,
QueryLowMemoryStrategy BIGINT NULL,
QueryOptimized BIGINT NULL,
QueryReused BIGINT NULL,
ReqCountActive BIGINT NULL,
ReqCountBlockContention BIGINT NULL,
ReqCountBlockIO BIGINT NULL,
ReqCountBlockLock BIGINT NULL,
ReqCountUnscheduled BIGINT NULL,
ReqStatus TEXT NULL,
ReqTimeActive DECIMAL (30, 6) NULL,
ReqTimeBlockContention DECIMAL (30, 6) NULL,
ReqTimeBlockIO DECIMAL (30, 6) NULL,
ReqTimeBlockLock DECIMAL (30, 6) NULL,
ReqTimeUnscheduled DECIMAL (30, 6) NULL,
ReqType TEXT NULL,
RequestsReceived BIGINT NULL,
Rlbk BIGINT NULL,
RollbackLogPages BIGINT NULL,
TempFilePages BIGINT NULL,
TransactionStartTime TEXT NOT NULL DEFAULT '1900-01-01',
UncommitOp BIGINT NULL,
Userid VARCHAR (128) NULL,
previous_ApproximateCPUTime DECIMAL (30, 6) NOT NULL DEFAULT 0.0,
interval_ApproximateCPUTime AS (COALESCE ("ApproximateCPUTime", 0) - previous_ApproximateCPUTime),
previous_Commit BIGINT NOT NULL DEFAULT 0,
interval_Commit AS (COALESCE ("Commit", 0) - previous_Commit),
previous_Rlbk BIGINT NOT NULL DEFAULT 0,
interval_Rlbk AS (COALESCE (Rlbk, 0) - previous_Rlbk))
這裏是SQL Anywhere 11中的目標表:
CREATE TABLE sa_t2 (
sampling_id BIGINT NOT NULL,
sample_set_number BIGINT NOT NULL,
connection_number BIGINT NOT NULL,
blocker_owner_table_name VARCHAR (257) NULL,
blocker_lock_type VARCHAR (32) NULL,
blocker_owner_name VARCHAR (128) NULL,
blocker_table_name VARCHAR (128) NULL,
blocker_reason TEXT NULL,
blocker_row_identifier VARCHAR (32) NULL,
current_engine_version TEXT NOT NULL,
page_size INTEGER NOT NULL,
ApproximateCPUTime DECIMAL (30, 6) NULL,
BlockedOn BIGINT NULL,
BytesReceived BIGINT NULL,
BytesSent BIGINT NULL,
CacheHits BIGINT NULL,
CacheRead BIGINT NULL,
"Commit" BIGINT NULL,
DiskRead BIGINT NULL,
DiskWrite BIGINT NULL,
FullCompare BIGINT NULL,
IndAdd BIGINT NULL,
IndLookup BIGINT NULL,
Isolation_level BIGINT NULL,
LastReqTime TEXT NOT NULL DEFAULT '1900-01-01',
LastStatement TEXT NULL,
LockCount BIGINT NULL,
LockName BIGINT NULL,
LockTableOID BIGINT NULL,
LoginTime TEXT NOT NULL DEFAULT '1900-01-01',
LogWrite BIGINT NULL,
Name VARCHAR (128) NULL,
NodeAddress TEXT NULL,
Prepares BIGINT NULL,
PrepStmt BIGINT NULL,
QueryLowMemoryStrategy BIGINT NULL,
QueryOptimized BIGINT NULL,
QueryReused BIGINT NULL,
ReqCountActive BIGINT NULL,
ReqCountBlockContention BIGINT NULL,
ReqCountBlockIO BIGINT NULL,
ReqCountBlockLock BIGINT NULL,
ReqCountUnscheduled BIGINT NULL,
ReqStatus TEXT NULL,
ReqTimeActive DECIMAL (30, 6) NULL,
ReqTimeBlockContention DECIMAL (30, 6) NULL,
ReqTimeBlockIO DECIMAL (30, 6) NULL,
ReqTimeBlockLock DECIMAL (30, 6) NULL,
ReqTimeUnscheduled DECIMAL (30, 6) NULL,
ReqType TEXT NULL,
RequestsReceived BIGINT NULL,
Rlbk BIGINT NULL,
RollbackLogPages BIGINT NULL,
TempFilePages BIGINT NULL,
TransactionStartTime TEXT NOT NULL DEFAULT '1900-01-01',
UncommitOp BIGINT NULL,
Userid VARCHAR (128) NULL,
previous_ApproximateCPUTime DECIMAL (30, 6) NOT NULL DEFAULT 0.0,
interval_ApproximateCPUTime DECIMAL (30, 6) NOT NULL COMPUTE (COALESCE ("ApproximateCPUTime", 0) - previous_ApproximateCPUTime),
previous_Commit BIGINT NOT NULL DEFAULT 0,
interval_Commit BIGINT NOT NULL COMPUTE (COALESCE ("Commit", 0) - previous_Commit),
previous_Rlbk BIGINT NOT NULL DEFAULT 0,
interval_Rlbk BIGINT NOT NULL COMPUTE (COALESCE (Rlbk, 0) - previous_Rlbk),
PRIMARY KEY (sample_set_number, connection_number));
我已經添加源和目標表的CREATE TABLE語句。進一步的實驗表明,各種數據類型可能是內存泄漏的原因;例如多個TEXT列,30位DECIMAL,計算的AS列等等。我從原始問題陳述中刪除DDL的PROFOUND APOLOGIES ...有點不公平。 – 2009-10-11 14:01:58
初步跡象表明,在源表中有多個TEXT列導致SQL Server內存泄漏。將除TEXT列之外的所有列都更改爲VARCHAR似乎有訣竅。完整測試高達250,000行,增加零內存;我會等待它完成,然後放置一個小的可重複性。 – 2009-10-11 15:10:41