SQL सर्वर nvarchar (अधिकतम) बनाम nvarchar (n) प्रदर्शन को प्रभावित करता है


16

यह SQL Server 2008 R2 SP2 है। मेरे पास 2 टेबल हैं। दोनों समान हैं (डेटा और इंडेक्सिंग), सिवाय इसके कि पहली तालिका में एक VALUE स्तंभ है nvarchar(max)और दूसरे के समान स्तंभ है nvarchar(800)। यह कॉलम गैर-संकुल सूचकांक में शामिल है। मैंने दोनों तालिकाओं पर एक गुच्छेदार सूचकांक भी बनाया। मैंने अनुक्रमणिका का पुनर्निर्माण भी किया है। इस स्तंभ में अधिकतम स्ट्रिंग लंबाई 650 है।

यदि मैं एक ही क्वेरी को दोनों nvarchar(800)टेबल के खिलाफ लगातार तेज करता हूं , तो कई बार दो बार तेजी से। निश्चित रूप से ऐसा लगता है कि यह "वर्चर" के उद्देश्य को हरा रहा है। तालिका में 800,000+ पंक्तियाँ हैं। क्वेरी को लगभग 110,000 पंक्तियों को देखना चाहिए (जो कि योजना का अनुमान है)।

Io के आंकड़ों के अनुसार कोई लोब रीड नहीं हैं, इसलिए सब कुछ पंक्ति में प्रतीत होता है। निष्पादन योजनाएं समान हैं, सिवाय इसके कि दो तालिकाओं के बीच लागत प्रतिशत में थोड़ा अंतर है और अनुमानित पंक्ति का आकार nvarchar(max)(91 बाइट्स बनाम 63 बाइट्स) के साथ बड़ा है । रीड की संख्या बहुत अधिक समान हैं।

अंतर क्यों?

===== स्कीमा ======

 CREATE TABLE [dbo].[table1](
        [ID] [bigint] IDENTITY(1,1) NOT NULL,
        [ProductID] [bigint] NOT NULL,
        [ProductSkeletonID] [bigint] NOT NULL,
        [Value] [nvarchar](max) NOT NULL,
        [IsKeywordSearchable] [bit] NULL,
        [ValueInteger] [bigint] NULL,
        [ValueDecimal] [decimal](18, 2) NULL,
        [ValueDate] [datetime] NULL,
        [TypeOfData] [nvarchar](20) NOT NULL,
     CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

    CREATE NONCLUSTERED INDEX [IX_table1_productskeletonid] ON [dbo].[table1] 
    (
        [ProductSkeletonID] ASC
    )
    INCLUDE ( [ProductID],
    [Value]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

    CREATE TABLE [dbo].[table2](
        [ID] [bigint] IDENTITY(1,1) NOT NULL,
        [ProductID] [bigint] NOT NULL,
        [ProductSkeletonID] [bigint] NOT NULL,
        [Value] [nvarchar](800) NOT NULL,
        [IsKeywordSearchable] [bit] NULL,
        [ValueInteger] [bigint] NULL,
        [ValueDecimal] [decimal](18, 2) NULL,
        [ValueDate] [datetime] NULL,
        [TypeOfData] [nvarchar](20) NOT NULL,
     CONSTRAINT [PK_table2] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    CREATE NONCLUSTERED INDEX [IX_table2_productskeletonid] ON [dbo].[table2] 
    (
        [ProductSkeletonID] ASC
    )
    INCLUDE ( [ProductID],
    [Value]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]


CREATE TABLE [dbo].[table_results](
    [SearchID] [bigint] NOT NULL,
    [RowNbr] [int] NOT NULL,
    [ProductID] [bigint] NOT NULL,
    [PermissionList] [varchar](250) NULL,
    [SearchWeight] [int] NULL,
 CONSTRAINT [PK_table_results] PRIMARY KEY NONCLUSTERED 
(
    [SearchID] ASC,
    [RowNbr] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_table_results_SearchID] ON [dbo].[cart_product_searches_results] 
(
    [SearchID] ASC
)
INCLUDE ( [ProductID]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

===== टेबल 1 क्वेरी ======

    SELECT cppev.ProductSkeletonID, cppev.Value, COUNT(*) AS Value FROM table1 cppev
    JOIN search_results cpsr ON cppev.ProductID = cpsr.ProductID AND cpsr.SearchID = 227568 
    WHERE cppev.ProductSkeletonID in (3191, 3160, 3158, 3201)
    GROUP BY cppev.ProductSkeletonID, cppev.Value

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'table1'. Scan count 4, logical reads 582, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'table_results'. Scan count 1, logical reads 82, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    SQL Server Execution Times:
       CPU time = 1373 ms,  elapsed time = 1576 ms.

 |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1008],0)))
       |--Stream Aggregate(GROUP BY:([cppev].[Value], [cppev].[ProductSkeletonID]) DEFINE:([Expr1008]=Count(*)))
            |--Sort(ORDER BY:([cppev].[Value] ASC, [cppev].[ProductSkeletonID] ASC))
                 |--Hash Match(Inner Join, HASH:([cpsr].[ProductID])=([cppev].[ProductID]), RESIDUAL:([dbo].[table1].[ProductID] as [cppev].[ProductID]=[dbo].[table_results].[ProductID] as [cpsr].[ProductID]))
                      |--Index Seek(OBJECT:([dbo].[table_results].[IX_table_results_SearchID] AS [cpsr]), SEEK:([cpsr].[SearchID]=(227568)) ORDERED FORWARD)
                      |--Index Seek(OBJECT:([dbo].[table1].[IX_table1_productskeletonid] AS [cppev]), SEEK:([cppev].[ProductSkeletonID]=(3158) OR [cppev].[ProductSkeletonID]=(3160) OR [cppev].[ProductSkeletonID]=(3191) OR [cppev].[ProductSkeletonID]=(3201)) ORDERED FORWARD)

===== टेबल 2 क्वेरी ======

    SELECT cppev.ProductSkeletonID, cppev.Value, COUNT(*) AS Value FROM table2 cppev
    JOIN table_results cpsr ON cppev.ProductID = cpsr.ProductID AND cpsr.SearchID = 227568 
    WHERE cppev.ProductSkeletonID in (3191, 3160, 3158, 3201)
    GROUP BY cppev.ProductSkeletonID, cppev.Value

    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'table2'. Scan count 4, logical reads 584, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'table_results'. Scan count 1, logical reads 82, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    SQL Server Execution Times:
       CPU time = 484 ms,  elapsed time = 796 ms.

  |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1008],0)))
       |--Stream Aggregate(GROUP BY:([cppev].[Value], [cppev].[ProductSkeletonID]) DEFINE:([Expr1008]=Count(*)))
            |--Sort(ORDER BY:([cppev].[Value] ASC, [cppev].[ProductSkeletonID] ASC))
                 |--Hash Match(Inner Join, HASH:([cpsr].[ProductID])=([cppev].[ProductID]), RESIDUAL:([auctori_core_v40_D].[dbo].[table2].[ProductID] as [cppev].[ProductID]= [dbo].[table2].[ProductID] as [cpsr].[ProductID]))
                      |--Index Seek(OBJECT:([dbo].[table_results].[IX_table_results_SearchID] AS [cpsr]), SEEK:([cpsr].[SearchID]=(227568)) ORDERED FORWARD)
                      |--Index Seek(OBJECT:([dbo].[table2].[IX_table2_productskeletonid] AS [cppev]), SEEK:([cppev].[ProductSkeletonID]=(3158) OR [cppev].[ProductSkeletonID]=(3160) OR [cppev].[ProductSkeletonID]=(3191) OR [cppev].[ProductSkeletonID]=(3201)) ORDERED FORWARD)

4
क्वेरी, टेबल स्कीमा, नमूना या सांकेतिक डेटा और प्रत्येक क्वेरी के लिए निष्पादन योजनाएं। "मुझे नहीं लगता ..." ऐसा नहीं है "निश्चित रूप से नहीं है ..."।
मार्क स्टोरी-स्मिथ

आपके पास SQL ​​सर्वर का कौन सा संस्करण है?
मैक्स वर्नोन

Nvarchar (अधिकतम) फ़ील्ड के लिए पंक्ति संग्रहण के बारे में जानकारी के लिए Technet.microsoft.com/en-us/library/ms189087(v=SQL.105).aspx देखें । उन क्षेत्रों में वास्तविक डेटा कितना बड़ा है?
मैक्स वर्नोन

मैंने उपरोक्त प्रतिक्रिया को संबोधित करने के लिए पोस्ट को अपडेट किया।
ब्रायन बोहल

जवाबों:


14

आप MAXप्रकारों के उपयोग की लागत को देख रहे हैं ।

जबकि TSQL में NVARCHAR(MAX)समान है NVARCHAR(n)और इन-रो स्टोर किया जा सकता है, इसे अलग से स्टोरेज इंजन द्वारा नियंत्रित किया जाता है क्योंकि इसे ऑफ-रो में धकेला जा सकता है। जब ऑफ-पंक्ति यह LOB_DATAआवंटन इकाई के बजाय एक आवंटन इकाई होती है ROW_OVERFLOW_DATAऔर हम आपकी टिप्पणियों से मान सकते हैं कि यह ओवरहेड वहन करती है।

आप देख सकते हैं कि दो प्रकार के आंतरिक रूप से थोड़ा DBCC पेज स्पेलुनकिंग के साथ अलग-अलग संग्रहीत किया जाता है । मार्क रासमुसेन ने उदाहरण पृष्ठ को पोस्ट किया है जो विभिन्नताओं को दिखाता है कि किस प्रकार के लोब पॉइंटर का आकार (MAX) प्रकार के लिए है जैसे कि वर्चर, वैरबिनरी, आदि?

हम शायद यह मान सकते हैं कि यह GROUP BYउस MAXस्तंभ पर है जो आपके मामले में प्रदर्शन अंतर का कारण बनता है। मैंने अन्य प्रचालनों का एक MAXप्रकार से परीक्षण नहीं किया है, लेकिन ऐसा करना दिलचस्प हो सकता है और देखें कि क्या समान परिणाम देखे जाते हैं।


तो आप कह रहे हैं कि एक अतिरिक्त संसाधन [BLOB इनलाइन डेटा] बनाम एक सादे 'ol varchar रीडिंग है? मैं महत्वपूर्ण ओवरहेड की उम्मीद कर रहा था अगर यह पंक्ति से बाहर चला गया, लेकिन यह सभी डेटा इनलाइन है (dbcc इंडस्ट्रीज़ का उपयोग किया जाता है)। और आपको क्यों लगता है कि समूह इसे बाहर लाता है?
ब्रायन बोहल

इसे पढ़ने के लिए थोड़ा उपरिलेख, इस पर किसी भी गणना के लिए बहुत सारे जैसे GROUP BY। @RemusRusanu संभावना कुछ अंतर्दृष्टि की पेशकश कर सकता है (वह उम्मीद है कि पिंग देखेंगे)।
मार्क स्टोरी-स्मिथ

मैंने दूसरा पाया लेख जो समान व्यवहार और समान और समान पर भी दस्तावेज़ प्रस्तुत करता है। मुझे आश्चर्य है कि अगर nvarchar (अधिकतम) एक कम कुशल एल्गोरिदम का उपयोग करता है।
ब्रायन बोहल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.