अत्यधिक सॉर्ट मेमोरी अनुदान


45

इस सरल क्वेरी को इतनी स्मृति क्यों दी गई है?

-- Demo table
CREATE TABLE dbo.Test
(
    TID integer IDENTITY NOT NULL,
    FilterMe integer NOT NULL,
    SortMe integer NOT NULL,
    Unused nvarchar(max) NULL,

    CONSTRAINT PK_dbo_Test_TID
    PRIMARY KEY CLUSTERED (TID)
);
GO
-- 100,000 example rows
INSERT dbo.Test WITH (TABLOCKX)
    (FilterMe, SortMe)
SELECT TOP (100 * 1000)
    CHECKSUM(NEWID()) % 1000,
    CHECKSUM(NEWID())
FROM sys.all_columns AS AC1
CROSS JOIN sys.all_columns AS AC2;
GO    
-- Query
SELECT
    T.TID,
    T.FilterMe,
    T.SortMe,
    T.Unused
FROM dbo.Test AS T 
WHERE 
    T.FilterMe = 567
ORDER BY 
    T.SortMe;

अनुमानित 50 पंक्तियों के लिए, ऑप्टिमाइज़र के पास लगभग 500 एमबी का भंडार होता है:

अनुमानित योजना

जवाबों:


42

यह SQL सर्वर में एक बग (2008 से 2014 तक समावेशी) है।

मेरी बग रिपोर्ट यहाँ है ।

फ़िल्टरिंग स्थिति को अवशिष्ट विधेय के रूप में स्कैन ऑपरेटर में नीचे धकेल दिया जाता है, लेकिन इस प्रकार के लिए दी गई मेमोरी को पूर्व-फ़िल्टर कार्डिनलिटी अनुमान के आधार पर गलत तरीके से गणना की जाती है ।

समस्या का वर्णन करने के लिए, हम फ़िल्टर को ऑपरेटर से नीचे धकेलने से रोकने के लिए (undocumented और असमर्थित) ट्रेस ध्वज 9130 का उपयोग कर सकते हैं । छांटने के लिए दी गई मेमोरी अब फ़िल्टर आउटपुट की अनुमानित कार्डिनैलिटी के आधार पर सही ढंग से है, स्कैन के लिए नहीं:

SELECT
    T.TID,
    T.FilterMe,
    T.SortMe,
    T.Unused
FROM dbo.Test AS T 
WHERE 
    T.FilterMe = 567
ORDER BY 
    T.SortMe
OPTION (QUERYTRACEON 9130); -- Not for production systems!

अनुमानित योजना

एक उत्पादन प्रणाली के लिए , समस्याग्रस्त योजना के आकार (एक अन्य स्तंभ पर एक प्रकार के साथ एक स्कैन में धकेल दिया गया फिल्टर) से बचने के लिए कदम उठाने होंगे । ऐसा करने का एक तरीका फ़िल्टर स्थिति पर एक सूचकांक प्रदान करना और / या आवश्यक सॉर्ट क्रम प्रदान करना है।

-- Index on the filter condition only
CREATE NONCLUSTERED INDEX IX_dbo_Test_FilterMe
ON dbo.Test (FilterMe);

इस अनुक्रमणिका के साथ, सॉर्ट के लिए वांछित मेमोरी अनुदान केवल 928KB है :

फ़िल्टर सूचकांक के साथ

आगे जाकर, निम्नलिखित सूचकांक पूरी तरह से ( शून्य मेमोरी अनुदान) से बच सकते हैं :

-- Provides filtering and sort order
-- nvarchar(max) column deliberately not INCLUDEd
CREATE NONCLUSTERED INDEX IX_dbo_Test_FilterMe_SortMe
ON dbo.Test (FilterMe, SortMe);

फ़िल्टर और सॉर्ट इंडेक्स के साथ

SQL Server x64 डेवलपर संस्करण के निम्न बिल्ड पर परीक्षण और बग की पुष्टि की गई है:

2014   : 12.00.2430 (RTM CU4)
2012   : 11.00.5556 (SP2 CU3)
2008R2 : 10.50.6000 (SP3)
2008   : 10.00.6000 (SP4)

यह SQL Server 2016 सर्विस पैक 1 में ठीक किया गया था । रिलीज नोटों में निम्नलिखित शामिल हैं:

VSTS बग नंबर 8024987
टेबल स्कैन और इंडेक्स स्कैन पुश डाउन के साथ पैरेंट ऑपरेटर के लिए मैमोरी ग्रांट को ओवरएस्टीमेट करते हैं।

परीक्षण किया गया और पुष्टि की गई:

  • Microsoft SQL Server 2016 (SP1) - 13.0.4001.0 (X64) Developer Edition
  • Microsoft SQL Server 2014 (SP2-CU3) 12.0.5538.0 (X64) Developer Edition

दोनों CE मॉडल।


5

SQL 2012 के बाद से आप के बीच एक बड़ी विसंगति के लिए देख सकते हैं , SerialRequiredMemoryऔर SerialDesiredMemoryकुछ इस तरह:

-- Search plan cache for Memory Grant issues
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp

-- Collect more info about the plan here if required, eg usecounts, objtype etc, 
SELECT IDENTITY( INT, 1, 1 ) rowId, query_plan
INTO #tmp
FROM sys.dm_exec_cached_plans cp WITH(NOLOCK)
    CROSS APPLY sys.dm_exec_query_plan(plan_handle)
GO


;WITH cte AS
(
SELECT
    rowId,
    query_plan,
    m.c.value ('@SerialRequiredMemory', 'INT' ) AS SerialRequiredMemory,
    m.c.value ('@SerialDesiredMemory', 'INT' ) AS SerialDesiredMemory

FROM #tmp t
    CROSS APPLY t.query_plan.nodes ( '//*:MemoryGrantInfo[@SerialDesiredMemory[. > 0]]' ) m(c)
), cte2 AS (
SELECT *,
    CAST( CAST( SerialDesiredMemory AS DECIMAL(10,2) ) / CAST( SerialRequiredMemory AS DECIMAL(10,2) ) AS DECIMAL(10,2) ) Desired_to_Required_ratio
FROM cte
)
SELECT TOP 20
    rowId,
    query_plan,
    SerialRequiredMemory SerialRequiredMemory_KB,
    SerialDesiredMemory SerialDesiredMemory_KB,
    CAST( SerialRequiredMemory / 1024. AS DECIMAL(10,2) ) SerialRequiredMemory_MB,
    CAST( SerialDesiredMemory / 1024. AS DECIMAL(10,2) ) SerialDesiredMemory_MB,
    Desired_to_Required_ratio
FROM cte2
WHERE Desired_to_Required_ratio > 100
ORDER BY Desired_to_Required_ratio DESC

इन नई विशेषताओं पर कुछ और नोट यहां दिए गए हैं । यह क्वेरी थोड़ी खुरदरी और तैयार है, लेकिन 975.47 के साथ ही आई-पॉपिंग योजनाओं के एक जोड़े के अनुपात में मेरे एसक्यूएल सर्वर 2014 देव बॉक्स से अत्यधिक सॉर्ट क्वेरी को उठाया। 'सामान्य' अनुपात (कम से कम मेरे सीमित परीक्षण से) ~ 1 लगता है।

HTH


3

पूरी सहायताके लिए शुक्रिया। मुझे लगा कि मैं उपरोक्त क्वेरी का एक अद्यतन संस्करण भेजूंगा जो हमें मददगार लगा।

-- Search plan cache for Memory Grant issues
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp

-- Collect more info about the plan here if required, eg usecounts, objtype etc, 
SELECT IDENTITY( INT, 1, 1 ) rowId, query_plan, db = DB_NAME(CAST(pa.value AS int))
INTO #tmp
FROM sys.dm_exec_cached_plans cp WITH(NOLOCK)
    CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle)
    OUTER APPLY sys.dm_exec_plan_attributes(cp.plan_handle) pa 
    WHERE pa.attribute = 'dbid' 
GO

;WITH cte AS
(
SELECT
    rowId,
    query_plan,
    m.c.value ('@SerialRequiredMemory', 'INT' ) AS SerialRequiredMemory,
    m.c.value ('@SerialDesiredMemory', 'INT' ) AS SerialDesiredMemory,
    db
FROM #tmp t
    CROSS APPLY t.query_plan.nodes ( '//*:MemoryGrantInfo[@SerialDesiredMemory[. > 0]]' ) m(c)
), cte2 AS (
SELECT *,
    CAST( CAST( SerialDesiredMemory AS DECIMAL(10,2) ) / CAST( SerialRequiredMemory AS DECIMAL(10,2) ) AS DECIMAL(10,2) ) Desired_to_Required_ratio
FROM cte
)
SELECT TOP 20
    rowId,
    query_plan,
    SerialRequiredMemory SerialRequiredMemory_KB,
    SerialDesiredMemory SerialDesiredMemory_KB,
    CAST( SerialRequiredMemory / 1024. AS DECIMAL(10,2) ) SerialRequiredMemory_MB,
    CAST( SerialDesiredMemory / 1024. AS DECIMAL(10,2) ) SerialDesiredMemory_MB,
    Desired_to_Required_ratio,
    db
FROM cte2
WHERE Desired_to_Required_ratio > 100
ORDER BY Desired_to_Required_ratio DESC
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.