SQL Server 2008 Linked Server i ad-hoc Wstawki spowodować gwałtowny wyciek pamięci, który ostatecznie powoduje, że serwer przestanie odpowiadać, a kończy się z powodu następującego błędu:mało pamięci systemowej w puli zasobów „wewnętrzną”
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
Serwer nie reaguje do czasu zrestartowania serwera SQL.
Software w użyciu:
Windows Vista Ultimate 64-bitowy build 6001 SP1
Microsoft SQL Server 2008 (SP1) - 10.0.2734.0 (X64) 11 września 2009 14:30:58 copyright (c) 1988-2008 Microsoft Corporation Express Edition z Advanced Services (64-bit) w systemie Windows NT 6.0 (Build 6001: Service pack 1)
SAOLEDB.11 sterownik z SQL Anywhere 11.0.1.2276
Ustawianie maks pamięci serwera (MB) 2048 nie pomogło.
dodanie różnych wartości -g (np -g256;) do serwera uruchamiania Parametry nie pomoże.
Używanie DBCC FREESYSTEMCACHE ("ALL"), DBCC FREESESSIONIONCACHE i DBCC FREEPROCCACHE nie pomogło.
Instalacja pakietu aktualizacji Cumnulative 4 do SQL Server 2008 z dodatkiem Service Pack 1 nie pomogło, mimo że zawierała poprawki do objaw wycieku pamięci udziałem Linked użycia serwera.
Oddzielenie wybrać ... ROW_NUMBER() OVER ... zapytania z INSERT nie pomogło. Eksperymentacja wykazała, że złożony SELECT nie spowodował wycieku pamięci, zrobił to INSERT.
Zmiana kodu użyć ad-hoc „insert into OPENROWSET” składni zamiast połączonego serwera nie pomogło; poniższy kod pokazuje połączone użycie serwera.
Narzędzie do analizy procesu sysinternals.com pokazuje, że użycie pamięci było powiązane z programem sqlserver.exe, a nie z bibliotekami DLL używanymi przez sterownik OLEDB SQL Anywhere SQL.
Należy zauważyć, że wersja połączonego serwera SQL Anywhere (tabele proxy) działa poprawnie, aby "wyciągnąć" 1,9 miliona wierszy z tabeli programu SQL Server 2008 do bazy danych SQL Anywhere 11 w pojedynczej transakcji. Przedstawiona tutaj logika to próba użycia funkcji połączonego serwera do "wypchnięcia" wierszy; ten sam kierunek, inna składnia.
Poniższy kod; 4G RAM jest wyczerpana po trzech lub czterech uruchomieniami copy_mss_t2 WYKONAJ:
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
Oto tabeli SQL źródło Serwer zawierający około 1 g danych w 1,9 miliona rzędach
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))
Oto tabela docelowa w 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));
Dodałem CREATE TABLE dla tabel źródłowych i docelowych. Dalsze eksperymenty wskazują, że różnorodność typów danych może być przyczyną wycieku pamięci; np. wiele kolumn TEXT, 30-cyfrowy DECIMAL, obliczone kolumny AS i tak dalej. Moje APROSZENIA Z APROBATÓW dla pominięcia DDL z oryginalnego stwierdzenia problemu ... trochę niesprawiedliwe. –
Wstępne wskazania mówią, że posiadanie wielu kolumn TEXT w tabeli źródłowej powoduje wyciek pamięci serwera SQL. Zmiana wszystkich kolumn TEXT z wyjątkiem jednej na VARCHAR wydaje się zdziałać. Pełny test jest do 250 000 wierszy z zerowym wzrostem pamięci RAM; Zaczekam, aż się skończy, a potem złożę małą, powtarzalną. –