बड़े तालिकाओं पर SQL सर्वर क्वेरी प्रदर्शन में सुधार


85

मेरे पास अपेक्षाकृत बड़ी तालिका है (वर्तमान में 2 मिलियन रिकॉर्ड) और जानना चाहूंगा कि क्या यह तदर्थ प्रश्नों के लिए प्रदर्शन में सुधार करना संभव है। शब्द तदर्थ यहाँ महत्वपूर्ण है। अनुक्रमणिका जोड़ना एक विकल्प नहीं है (स्तंभों पर पहले से ही अनुक्रमित हैं जो सबसे अधिक सामान्य रूप से उद्धृत हैं)।

100 सबसे हाल ही में अपडेट किए गए रिकॉर्ड को वापस करने के लिए एक सरल क्वेरी चल रही है:

select top 100 * from ER101_ACCT_ORDER_DTL order by er101_upd_date_iso desc

कई मिनट लगते हैं। नीचे निष्पादन योजना देखें:

यहां छवि विवरण दर्ज करें

तालिका स्कैन से अतिरिक्त विवरण:

यहां छवि विवरण दर्ज करें

SQL Server Execution Times:
  CPU time = 3945 ms,  elapsed time = 148524 ms.

सर्वर बहुत शक्तिशाली है (मेमोरी 48 जीबी रैम, 24 कोर प्रोसेसर से) एसक्यूएल सर्वर 2008 आर 2 एक्स 64 चला रहा है।

अपडेट करें

मुझे 1,000,000 कोड वाली तालिका बनाने के लिए यह कोड मिला। मुझे लगा कि मैं SELECT TOP 100 * FROM testEnvironment ORDER BY mailAddress DESCकुछ अलग सर्वरों पर चला सकता हूं ताकि पता लगाया जा सके कि सर्वर पर मेरी डिस्क एक्सेस स्पीड खराब थी या नहीं।

WITH t1(N) AS (SELECT 1 UNION ALL SELECT 1),
t2(N) AS (SELECT 1 FROM t1 x, t1 y),
t3(N) AS (SELECT 1 FROM t2 x, t2 y),
Tally(N) AS (SELECT TOP 98 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM t3 x, t3 y),
Tally2(N) AS (SELECT TOP 5 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM t3 x, t3 y),
Combinations(N) AS (SELECT DISTINCT LTRIM(RTRIM(RTRIM(SUBSTRING(poss,a.N,2)) + SUBSTRING(vowels,b.N,1)))
                    FROM Tally a
                    CROSS JOIN Tally2 b
                    CROSS APPLY (SELECT 'B C D F G H J K L M N P R S T V W Z SCSKKNSNSPSTBLCLFLGLPLSLBRCRDRFRGRPRTRVRSHSMGHCHPHRHWHBWCWSWTW') d(poss)
                    CROSS APPLY (SELECT 'AEIOU') e(vowels))
SELECT IDENTITY(INT,1,1) AS ID, a.N + b.N AS N
INTO #testNames
FROM Combinations a 
CROSS JOIN Combinations b;

SELECT IDENTITY(INT,1,1) AS ID, firstName, secondName
INTO #testNames2
FROM (SELECT firstName, secondName
      FROM (SELECT TOP 1000 --1000 * 1000 = 1,000,000 rows
            N AS firstName
            FROM #testNames
            ORDER BY NEWID()) a
      CROSS JOIN (SELECT TOP 1000 --1000 * 1000 = 1,000,000 rows
                  N AS secondName
                  FROM #testNames
                  ORDER BY NEWID()) b) innerQ;

SELECT firstName, secondName,
firstName + '.' + secondName + '@fake.com' AS eMail,
CAST((ABS(CHECKSUM(NEWID())) % 250) + 1 AS VARCHAR(3)) + ' ' AS mailAddress,
(ABS(CHECKSUM(NEWID())) % 152100) + 1 AS jID,
IDENTITY(INT,1,1) AS ID
INTO #testNames3
FROM #testNames2

SELECT IDENTITY(INT,1,1) AS ID, firstName, secondName, eMail, 
mailAddress + b.N + b.N AS mailAddress
INTO testEnvironment
FROM #testNames3 a
INNER JOIN #testNames b ON a.jID = b.ID;

--CLEAN UP USELESS TABLES
DROP TABLE #testNames;
DROP TABLE #testNames2;
DROP TABLE #testNames3;

लेकिन तीन परीक्षण सर्वरों पर क्वेरी लगभग तुरंत चली। क्या कोई इसे समझा सकता है?

यहां छवि विवरण दर्ज करें

अपडेट २

टिप्पणियों के लिए धन्यवाद- कृपया उन्हें आते रहें ... उन्होंने मुझे गैर-संकुल से प्राथमिक कुंजी सूचकांक को बदलने की कोशिश की, बजाय दिलचस्प (और अप्रत्याशित?) परिणामों के साथ।

गैर-संकुल:

यहां छवि विवरण दर्ज करें

SQL Server Execution Times:
  CPU time = 3634 ms,  elapsed time = 154179 ms.

क्लस्टर किया गया:

यहां छवि विवरण दर्ज करें

SQL Server Execution Times:
  CPU time = 2650 ms,  elapsed time = 52177 ms.

यह कैसे संभव है? Er101_upd_date_iso कॉलम पर एक इंडेक्स के बिना क्लस्टर इंडेक्स स्कैन का उपयोग कैसे किया जा सकता है?

अपडेट ३

जैसा कि अनुरोध किया गया है - यह तालिका स्क्रिप्ट बनाएं:

CREATE TABLE [dbo].[ER101_ACCT_ORDER_DTL](
    [ER101_ORG_CODE] [varchar](2) NOT NULL,
    [ER101_ORD_NBR] [int] NOT NULL,
    [ER101_ORD_LINE] [int] NOT NULL,
    [ER101_EVT_ID] [int] NULL,
    [ER101_FUNC_ID] [int] NULL,
    [ER101_STATUS_CDE] [varchar](2) NULL,
    [ER101_SETUP_ID] [varchar](8) NULL,
    [ER101_DEPT] [varchar](6) NULL,
    [ER101_ORD_TYPE] [varchar](2) NULL,
    [ER101_STATUS] [char](1) NULL,
    [ER101_PRT_STS] [char](1) NULL,
    [ER101_STS_AT_PRT] [char](1) NULL,
    [ER101_CHG_COMMENT] [varchar](255) NULL,
    [ER101_ENT_DATE_ISO] [datetime] NULL,
    [ER101_ENT_USER_ID] [varchar](10) NULL,
    [ER101_UPD_DATE_ISO] [datetime] NULL,
    [ER101_UPD_USER_ID] [varchar](10) NULL,
    [ER101_LIN_NBR] [int] NULL,
    [ER101_PHASE] [char](1) NULL,
    [ER101_RES_CLASS] [char](1) NULL,
    [ER101_NEW_RES_TYPE] [varchar](6) NULL,
    [ER101_RES_CODE] [varchar](12) NULL,
    [ER101_RES_QTY] [numeric](11, 2) NULL,
    [ER101_UNIT_CHRG] [numeric](13, 4) NULL,
    [ER101_UNIT_COST] [numeric](13, 4) NULL,
    [ER101_EXT_COST] [numeric](11, 2) NULL,
    [ER101_EXT_CHRG] [numeric](11, 2) NULL,
    [ER101_UOM] [varchar](3) NULL,
    [ER101_MIN_CHRG] [numeric](11, 2) NULL,
    [ER101_PER_UOM] [varchar](3) NULL,
    [ER101_MAX_CHRG] [numeric](11, 2) NULL,
    [ER101_BILLABLE] [char](1) NULL,
    [ER101_OVERRIDE_FLAG] [char](1) NULL,
    [ER101_RES_TEXT_YN] [char](1) NULL,
    [ER101_DB_CR_FLAG] [char](1) NULL,
    [ER101_INTERNAL] [char](1) NULL,
    [ER101_REF_FIELD] [varchar](255) NULL,
    [ER101_SERIAL_NBR] [varchar](50) NULL,
    [ER101_RES_PER_UNITS] [int] NULL,
    [ER101_SETUP_BILLABLE] [char](1) NULL,
    [ER101_START_DATE_ISO] [datetime] NULL,
    [ER101_END_DATE_ISO] [datetime] NULL,
    [ER101_START_TIME_ISO] [datetime] NULL,
    [ER101_END_TIME_ISO] [datetime] NULL,
    [ER101_COMPL_STS] [char](1) NULL,
    [ER101_CANCEL_DATE_ISO] [datetime] NULL,
    [ER101_BLOCK_CODE] [varchar](6) NULL,
    [ER101_PROP_CODE] [varchar](8) NULL,
    [ER101_RM_TYPE] [varchar](12) NULL,
    [ER101_WO_COMPL_DATE] [datetime] NULL,
    [ER101_WO_BATCH_ID] [varchar](10) NULL,
    [ER101_WO_SCHED_DATE_ISO] [datetime] NULL,
    [ER101_GL_REF_TRANS] [char](1) NULL,
    [ER101_GL_COS_TRANS] [char](1) NULL,
    [ER101_INVOICE_NBR] [int] NULL,
    [ER101_RES_CLOSED] [char](1) NULL,
    [ER101_LEAD_DAYS] [int] NULL,
    [ER101_LEAD_HHMM] [int] NULL,
    [ER101_STRIKE_DAYS] [int] NULL,
    [ER101_STRIKE_HHMM] [int] NULL,
    [ER101_LEAD_FLAG] [char](1) NULL,
    [ER101_STRIKE_FLAG] [char](1) NULL,
    [ER101_RANGE_FLAG] [char](1) NULL,
    [ER101_REQ_LEAD_STDATE] [datetime] NULL,
    [ER101_REQ_LEAD_ENDATE] [datetime] NULL,
    [ER101_REQ_STRK_STDATE] [datetime] NULL,
    [ER101_REQ_STRK_ENDATE] [datetime] NULL,
    [ER101_LEAD_STDATE] [datetime] NULL,
    [ER101_LEAD_ENDATE] [datetime] NULL,
    [ER101_STRK_STDATE] [datetime] NULL,
    [ER101_STRK_ENDATE] [datetime] NULL,
    [ER101_DEL_MARK] [char](1) NULL,
    [ER101_USER_FLD1_02X] [varchar](2) NULL,
    [ER101_USER_FLD1_04X] [varchar](4) NULL,
    [ER101_USER_FLD1_06X] [varchar](6) NULL,
    [ER101_USER_NBR_060P] [int] NULL,
    [ER101_USER_NBR_092P] [numeric](9, 2) NULL,
    [ER101_PR_LIST_DTL] [numeric](11, 2) NULL,
    [ER101_EXT_ACCT_CODE] [varchar](8) NULL,
    [ER101_AO_STS_1] [char](1) NULL,
    [ER101_PLAN_PHASE] [char](1) NULL,
    [ER101_PLAN_SEQ] [int] NULL,
    [ER101_ACT_PHASE] [char](1) NULL,
    [ER101_ACT_SEQ] [int] NULL,
    [ER101_REV_PHASE] [char](1) NULL,
    [ER101_REV_SEQ] [int] NULL,
    [ER101_FORE_PHASE] [char](1) NULL,
    [ER101_FORE_SEQ] [int] NULL,
    [ER101_EXTRA1_PHASE] [char](1) NULL,
    [ER101_EXTRA1_SEQ] [int] NULL,
    [ER101_EXTRA2_PHASE] [char](1) NULL,
    [ER101_EXTRA2_SEQ] [int] NULL,
    [ER101_SETUP_MSTR_SEQ] [int] NULL,
    [ER101_SETUP_ALTERED] [char](1) NULL,
    [ER101_RES_LOCKED] [char](1) NULL,
    [ER101_PRICE_LIST] [varchar](10) NULL,
    [ER101_SO_SEARCH] [varchar](9) NULL,
    [ER101_SSB_NBR] [int] NULL,
    [ER101_MIN_QTY] [numeric](11, 2) NULL,
    [ER101_MAX_QTY] [numeric](11, 2) NULL,
    [ER101_START_SIGN] [char](1) NULL,
    [ER101_END_SIGN] [char](1) NULL,
    [ER101_START_DAYS] [int] NULL,
    [ER101_END_DAYS] [int] NULL,
    [ER101_TEMPLATE] [char](1) NULL,
    [ER101_TIME_OFFSET] [char](1) NULL,
    [ER101_ASSIGN_CODE] [varchar](10) NULL,
    [ER101_FC_UNIT_CHRG] [numeric](13, 4) NULL,
    [ER101_FC_EXT_CHRG] [numeric](11, 2) NULL,
    [ER101_CURRENCY] [varchar](3) NULL,
    [ER101_FC_RATE] [numeric](12, 5) NULL,
    [ER101_FC_DATE] [datetime] NULL,
    [ER101_FC_MIN_CHRG] [numeric](11, 2) NULL,
    [ER101_FC_MAX_CHRG] [numeric](11, 2) NULL,
    [ER101_FC_FOREIGN] [numeric](12, 5) NULL,
    [ER101_STAT_ORD_NBR] [int] NULL,
    [ER101_STAT_ORD_LINE] [int] NULL,
    [ER101_DESC] [varchar](255) NULL
) ON [PRIMARY]
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PRT_SEQ_1] [varchar](12) NULL
SET ANSI_PADDING ON
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PRT_SEQ_2] [varchar](120) NULL
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TAX_BASIS] [char](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_RES_CATEGORY] [char](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_DECIMALS] [char](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TAX_SEQ] [varchar](7) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MANUAL] [char](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_LC_RATE] [numeric](12, 5) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_FC_RATE] [numeric](12, 5) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_PL_RATE] [numeric](12, 5) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_DIFF] [char](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_UNIT_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_EXT_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_MIN_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TR_MAX_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PL_UNIT_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PL_EXT_CHRG] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PL_MIN_CHRG] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PL_MAX_CHRG] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TAX_RATE_TYPE] [char](1) NULL
SET ANSI_PADDING ON
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ORDER_FORM] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_FACTOR] [int] NULL
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MGMT_RPT_CODE] [varchar](6) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ROUND_CHRG] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_WHOLE_QTY] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SET_QTY] [numeric](15, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SET_UNITS] [numeric](15, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SET_ROUNDING] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SET_SUB] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TIME_QTY] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_GL_DISTR_PCT] [numeric](7, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_REG_SEQ] [int] NULL
SET ANSI_PADDING ON
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ALT_DESC] [varchar](255) NULL
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_REG_ACCT] [varchar](8) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_DAILY] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_AVG_UNIT_CHRG] [varchar](1) NULL
SET ANSI_PADDING ON
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ALT_DESC2] [varchar](255) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_CONTRACT_SEQ] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ORIG_RATE] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_DISC_PCT] [decimal](17, 10) NULL
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_DTL_EXIST] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ORDERED_ONLY] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_STDATE] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_STTIME] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_ENDATE] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_ENTIME] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_RATE] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_UNITS] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_BASE_RATE] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_COMMIT_QTY] [numeric](11, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MM_QTY_USED] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MM_CHRG_USED] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_TEXT_1] [varchar](50) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_NBR_1] [numeric](13, 3) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_NBR_2] [numeric](13, 3) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_NBR_3] [numeric](13, 3) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PL_BASE_RATE] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_REV_DIST] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_COVER] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_RATE_TYPE] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_USE_SEASONAL] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TAX_EI] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TAXES] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_FC_TAXES] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PL_TAXES] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_FC_QTY] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_LEAD_HRS] [numeric](6, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_STRIKE_HRS] [numeric](6, 2) NULL
SET ANSI_PADDING ON
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_CANCEL_USER_ID] [varchar](10) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ST_OFFSET_HRS] [numeric](7, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_EN_OFFSET_HRS] [numeric](7, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MEMO_FLAG] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MEMO_EXT_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MEMO_EXT_CHRG_PL] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MEMO_EXT_CHRG_TR] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MEMO_EXT_CHRG_FC] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TIME_QTY_EDIT] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SURCHARGE_PCT] [decimal](17, 10) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_INCL_EXT_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_INCL_EXT_CHRG_FC] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_CARRIER] [varchar](6) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SETUP_ID2] [varchar](8) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHIPPABLE] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_CHARGEABLE] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_NBR_ALLOW] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_NBR_START] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_NBR_END] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_SUPPLIER] [varchar](8) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_TRACK_ID] [varchar](40) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_REF_INV_NBR] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_NEW_ITEM_STS] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MSTR_REG_ACCT_CODE] [varchar](8) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ALT_DESC3] [varchar](255) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ALT_DESC4] [varchar](255) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ALT_DESC5] [varchar](255) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SETUP_ROLLUP] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MM_COST_USED] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_AUTO_SHIP_RCD] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_FIXED] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ITEM_EST_TBD] [varchar](3) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ROLLUP_PL_UNIT_CHRG] [numeric](13, 4) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ROLLUP_PL_EXT_CHRG] [numeric](13, 2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_GL_ORD_REV_TRANS] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_DISCOUNT_FLAG] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SETUP_RES_TYPE] [varchar](6) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SETUP_RES_CODE] [varchar](12) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PERS_SCHED_FLAG] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PRINT_STAMP] [datetime] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SHOW_EXT_CHRG] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PRINT_SEQ_NBR] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_PAY_LOCATION] [varchar](3) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_MAX_RM_NIGHTS] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_USE_TIER_COST] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_UNITS_SCHEME_CODE] [varchar](6) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_ROUND_TIME] [varchar](2) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_LEVEL] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_SETUP_PARENT_ORD_LINE] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_BADGE_PRT_STS] [varchar](1) NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_EVT_PROMO_SEQ] [int] NULL
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD [ER101_REG_TYPE] [varchar](12) NULL
/****** Object:  Index [PK__ER101_ACCT_ORDER]    Script Date: 04/15/2012 20:24:37 ******/
ALTER TABLE [dbo].[ER101_ACCT_ORDER_DTL] ADD  CONSTRAINT [PK__ER101_ACCT_ORDER] PRIMARY KEY CLUSTERED 
(
    [ER101_ORD_NBR] ASC,
    [ER101_ORD_LINE] ASC,
    [ER101_ORG_CODE] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 50) ON [PRIMARY]

तालिका का आकार 2.8 जीबी है जिसमें सूचकांक आकार 3.9 जीबी है।


1
जब आप योजना मद पर माउस कर्सर मँडराते हैं तो बहुत कम संकेत होते हैं। वे अनुमानित I / O और CPU लागत दिखाते हैं। मैं पहली बार में I / O लागत के बारे में ध्यान रखूंगा।
ग्रेजेगॉर जीर्लिक

4
Table Scanएक ढेर को इंगित करता है (कोई क्लस्टर इंडेक्स नहीं) - इसलिए पहला कदम आपकी टेबल पर एक अच्छा, त्वरित क्लस्टर इंडेक्स जोड़ना होगा । दूसरा कदम पड़ताल करने के लिए हो सकता है कि क्या कोई गैर-अनुक्रमित सूचकांक er101_upd_date_isoमदद करेगा (और अन्य प्रदर्शन कमियों का कारण नहीं होगा)
marc_s

1
इसके लिए @marc_s धन्यवाद- मैंने संकुल सूचकांक को संकुल में बदल दिया है और इसने एक वित्तीय अंतर बना दिया है- क्या आप इसे स्पष्ट कर सकते हैं? (अपडेट 2 देखें)
ली टिकेट

2
खैर, क्लस्टर इंडेक्स सिर्फ टेबल के स्टोरेज लेआउट को बदलता है। क्लस्टर किए गए इंडेक्स में लीफ लेवल नोड्स में वास्तविक टेबल डेटा होता है - अर्थात: संपूर्ण तालिका को पढ़ने के लिए, SQL सर्वर अब एक क्लस्टर इंडेक्स स्कैन (मूल रूप से क्लस्टर इंडेक्स वाली टेबल पर "टेबल स्कैन") कर रहा है। यह लगभग हमेशा एक ढेर पर टेबल स्कैन (क्लस्टर किए गए सूचकांक के बिना) करने की तुलना में काफी तेज होने वाला है। यदि आपने अब er101_upd_date_isoकॉलम पर एक गैर-अनुक्रमित इंडेक्स जोड़ा है , तो आप संभवतः अपने निष्पादन योजना में "सॉर्ट" ऑपरेशन से छुटकारा पा सकते हैं और चीजों को और भी तेज कर सकते हैं
marc_s

2
@ लॉकेट, कृपया अपनी तालिका और सूचकांक परिभाषाएँ दिखाएं। विचार करने के लिए कई कारक हैं और कोई भी उनके लिए पूछ रहा है (जो मुझे आश्चर्यचकित करता है लेकिन शायद ऐसा नहीं करना चाहिए)। मैं आपको बता सकता हूं कि 2 मिलियन पंक्तियां बड़ी नहीं हैं और 200 मिलियन + पंक्तियों के साथ ठीक से अनुक्रमित तालिकाओं की तुलना में तेजी से वापसी होती है। सबसे अधिक संभावना है कि क्लस्टर इंडेक्स (अब आपके पास marc_s के लिए धन्यवाद है) एक खराब विकल्प है, लेकिन बारीकियों को देखे बिना कहना मुश्किल है। विभाजन का उपयोग न करें, लेकिन SET STATISTICS IO ON का उपयोग करें और संदेश टैब में तार्किक पुस्तकें जांचें। यदि कोई परिवर्तन लॉजिकल रीड्स को कम करता है तो आप करीब आ रहे हैं।
सोलोमन रटज़की

जवाबों:


59

सरल उत्तर: नहीं। आप Clustered Index पर 50% Fill Factor के साथ 238 कॉलम टेबल पर तदर्थ प्रश्नों की मदद नहीं कर सकते।

विस्तृत जवाब:

जैसा कि मैंने इस विषय पर अन्य उत्तरों में कहा है, इंडेक्स डिज़ाइन कला और विज्ञान दोनों है और इस बात पर विचार करने के लिए बहुत सारे कारक हैं कि कुछ, यदि कोई हो, कठिन और तेज़ नियम हैं। आपको विचार करने की आवश्यकता है: डीएमएल संचालन की मात्रा बनाम चयन, डिस्क सबसिस्टम, टेबल पर अन्य सूचकांक / ट्रिगर, तालिका के भीतर डेटा का वितरण, SARGable WHERE की शर्तों का उपयोग करते हुए प्रश्न हैं, और कई अन्य चीजें जो मुझे ठीक से याद भी नहीं हैं। अभी।

मैं यह कह सकता हूं कि इस विषय पर प्रश्नों के लिए कोई सारणी, इसकी अनुक्रमणिका, ट्रिगर, आदि की समझ के बिना कोई मदद नहीं दी जा सकती है। अब जब आपने तालिका परिभाषा पोस्ट की है (अभी भी अनुक्रमणिका पर प्रतीक्षा कर रहा है लेकिन तालिका परिभाषा अकेले इंगित करती है) 99% समस्या) मैं कुछ सुझाव दे सकता हूं।

सबसे पहले, यदि टेबल की परिभाषा सटीक है (238 कॉलम, 50% फिल फैक्टर) तो आप यहाँ उत्तर / सलाह के बाकी हिस्सों को बहुत अधिक अनदेखा कर सकते हैं; ;-)। यहाँ कम-से-राजनीतिक होने के लिए क्षमा करें, लेकिन गंभीरता से, यह बारीकियों को जानने के बिना एक जंगली हंस पीछा है। और अब जब हम तालिका की परिभाषा देखते हैं तो यह थोड़ा स्पष्ट हो जाता है कि क्यों एक साधारण क्वेरी को इतना लंबा समय लगेगा, तब भी जब परीक्षण क्वेरी (अपडेट # 1) इतनी जल्दी चली।

यहां मुख्य समस्या (और कई खराब प्रदर्शन स्थितियों में) खराब डेटा मॉडलिंग है। 238 कॉलम निषिद्ध नहीं हैं, जैसे कि 999 इंडेक्स निषिद्ध नहीं हैं, लेकिन यह आमतौर पर बहुत बुद्धिमान नहीं है।

अनुशंसाएँ:

  1. सबसे पहले, इस तालिका को वास्तव में फिर से तैयार करने की आवश्यकता है। यदि यह एक डेटा वेयरहाउस टेबल है, तो हो सकता है, लेकिन यदि नहीं तो इन क्षेत्रों को वास्तव में कई तालिकाओं में विभाजित करने की आवश्यकता होती है जो सभी में एक ही पीके हो सकते हैं। आपके पास एक मास्टर रिकॉर्ड तालिका होगी और बच्चे की टेबल सामान्यतः संबंधित विशेषताओं के आधार पर निर्भर जानकारी होती है और उन तालिकाओं के पीके मास्टर टेबल के पीके के समान होते हैं और इसलिए मास्टर टेबल के लिए भी एफके। मास्टर और सभी चाइल्ड टेबल के बीच 1-टू -1 संबंध होगा।
  2. के उपयोग ANSI_PADDING OFF, परेशान कर रहा है समय के साथ विभिन्न कॉलम जोड़ने की वजह से तालिका में असंगत उल्लेख करने के लिए नहीं। निश्चित नहीं है कि आप इसे अभी ठीक कर सकते हैं, लेकिन आदर्श रूप से आपके पास हमेशा होगा ANSI_PADDING ON, या बहुत कम से कम सभी ALTER TABLEबयानों में एक ही सेटिंग होगी ।
  3. 2 अतिरिक्त फ़ाइल समूह बनाने पर विचार करें: टेबल्स और इंडेक्स। अपने सामान को नहीं रखना सबसे अच्छा PRIMARYहै, जहां SQL SERVER अपने सभी डेटा और मेटा-डेटा को आपकी वस्तुओं के बारे में संग्रहीत करता है। आप अपना टेबल और क्लस्टर किए गए इंडेक्स बनाते हैं (जैसा कि टेबल के लिए डेटा है) पर [Tables]और सभी गैर-क्लस्टर इंडेक्स पर[Indexes]
  4. फिल फैक्टर 50% से बढ़ाएँ। यह कम संख्या होने की संभावना है कि आपका सूचकांक स्थान आपके डेटा स्थान से बड़ा क्यों है। एक अनुक्रमणिका पुनर्निर्माण करना आपके डेटा के लिए उपयोग किए गए अधिकतम 4k (कुल 8k पृष्ठ आकार में से) के साथ डेटा पृष्ठों को फिर से बनाएगा ताकि आपकी तालिका एक विस्तृत क्षेत्र में फैल जाए।
  5. यदि अधिकांश या सभी प्रश्नों की WHEREस्थिति में "ER101_ORG_CODE" है , तो इसे क्लस्टर इंडेक्स के अग्रणी स्तंभ पर ले जाने पर विचार करें। यह मानते हुए कि यह "ER101_ORD_NBR" की तुलना में अधिक बार उपयोग किया जाता है। यदि "ER101_ORD_NBR" का उपयोग अधिक बार किया जाता है, तो इसे रखें। ऐसा लगता है कि यह मानते हुए कि क्षेत्र के नाम का अर्थ "ऑर्गनाइजेशन कोड" और "ऑर्डरनंबर" है, "ऑर्गकोड" एक बेहतर समूहीकरण है जिसके भीतर कई "ऑर्डरन्यूट" हो सकते हैं।
  6. माइनर पॉइंट, लेकिन अगर "ER101_ORG_CODE" हमेशा 2 वर्ण का होता है, तो CHAR(2)इसके बजाय इसका उपयोग करें VARCHAR(2)क्योंकि यह पंक्ति हेडर में एक बाइट को बचाएगा जो चर चौड़ाई आकारों को ट्रैक करता है और लाखों पंक्तियों को जोड़ता है।
  7. जैसा कि यहां अन्य लोगों ने उल्लेख किया है, उपयोग SELECT *से प्रदर्शन को नुकसान होगा। न केवल इसके कारण SQL सर्वर को सभी कॉलमों को वापस करने की आवश्यकता होती है और इसलिए आपके अन्य अनुक्रमितों की परवाह किए बिना Clustered Index Scan करने की अधिक संभावना होती है, लेकिन यह SQL सर्वर समय सारणी में जाने और *सभी कॉलम नामों में अनुवाद करने के लिए भी लेता है। । यह सूची में सभी 238 स्तंभ नामों को निर्दिष्ट करने के लिए थोड़ा तेज़ होना चाहिए, SELECTहालांकि यह स्कैन समस्या में मदद नहीं करेगा। लेकिन क्या आपको वास्तव में वैसे भी सभी 238 स्तंभों की आवश्यकता है?

सौभाग्य!

UPDATE
प्रश्न की पूर्णता के लिए "तदर्थ प्रश्नों के लिए एक बड़ी तालिका में प्रदर्शन में सुधार कैसे करें", यह ध्यान दिया जाना चाहिए कि जबकि यह इस विशिष्ट मामले के लिए मदद नहीं करेगा, यदि कोई SQL Server 2012 का उपयोग कर रहा है (या नया जब वह समय आता है) और यदि तालिका अपडेट नहीं की जा रही है, तो Columnstore Indexes का उपयोग करना एक विकल्प है। उस नई सुविधा के बारे में अधिक जानकारी के लिए, यहां देखें: http://msdn.microsoft.com/en-us/library/gg492088.aspx (मेरा मानना ​​है कि ये SQL Server 2014 में शुरू होने वाले अपग्रेडेबल थे)।

अद्यतन 2
अतिरिक्त विचार हैं:

  • क्लस्टर किए गए अनुक्रमणिका पर संपीड़न सक्षम करें। यह विकल्प SQL Server 2008 में उपलब्ध था, लेकिन एंटरप्राइज़ संस्करण-केवल सुविधा के रूप में। हालाँकि, SQL Server 2016 SP1 के रूप में , डेटा संपीड़न सभी संस्करणों में उपलब्ध कराया गया था ! कृपया पंक्ति और पृष्ठ संपीड़न पर विवरण के लिए डेटा संपीड़न के लिए MSDN पृष्ठ देखें।
  • आप डेटा संपीड़न का उपयोग नहीं कर सकते हैं, या अगर यह ज्यादा लाभ एक विशेष तालिका के लिए प्रदान करेगा नहीं है, तो आप एक निश्चित लंबाई प्रकार का एक स्तंभ है ( INT, BIGINT, TINYINT, SMALLINT, CHAR, NCHAR, BINARY, DATETIME, SMALLDATETIME, MONEY, आदि) और अच्छी तरह से 50 से अधिक % पंक्तियाँ हैं NULL, फिर SPARSESQL Server 2008 में उपलब्ध विकल्प को सक्षम करने पर विचार करें। कृपया विवरण के लिए उपयोग विरल कॉलम के लिए MSDN पृष्ठ देखें।

बिंदु 7 व्यक्तिगत रूप से पर मैं कल्पना है कि यह 238 स्तंभ नाम मेटाडाटा से पार्स से उन्हें क्वेरी पाठ से बाहर जोड़ने के लिए तेजी से होना चाहिए और फिर वैसे भी मेटाडाटा जाँच करने के लिए है सुनिश्चित करने के लिए वे सब exist.There के खिलाफ मजबूत पर्याप्त तर्क हैं *बिना कि संदिग्ध एक
मार्टिन स्मिथ

53

इस क्वेरी के साथ कुछ समस्याएँ हैं (और यह प्रत्येक क्वेरी पर लागू होती है)।

सूचकांक का अभाव

er101_upd_date_isoस्तंभ पर अनुक्रमणिका का अभाव सबसे महत्वपूर्ण बात है क्योंकि ओड ने पहले ही उल्लेख किया है।

मिलान सूचकांक के बिना (जिसमें टेबल स्कैन की कमी हो सकती है) बड़ी तालिकाओं पर तेज क्वेरी चलाने का कोई मौका नहीं है।

यदि आप अनुक्रमणिका नहीं जोड़ सकते हैं (विभिन्न कारणों से जिनमें सिर्फ एक तदर्थ क्वेरी के लिए अनुक्रमणिका बनाने का कोई मतलब नहीं है ) तो मैं कुछ वर्कअराउंड (जो तदर्थ प्रश्नों के लिए इस्तेमाल किया जा सकता है) का सुझाव दूंगा:

1. अस्थायी तालिकाओं का उपयोग करें

जिन डेटा में आप रुचि रखते हैं, उनकी सबसेट (पंक्तियों और स्तंभों) पर अस्थायी तालिका बनाएं। अस्थायी तालिका बहुत छोटी होनी चाहिए जो मूल स्रोत तालिका, आसानी से अनुक्रमित की जा सके (यदि आवश्यक हो) और उस डेटा के सबसेट को कैश किया जा सकता है जिसमें आप रुचि रखते हैं।

अस्थायी तालिका बनाने के लिए आप कोड का उपयोग कर सकते हैं (परीक्षण नहीं किया गया):

-- copy records from last month to temporary table
INSERT INTO
   #my_temporary_table
SELECT
    *
FROM
    er101_acct_order_dtl WITH (NOLOCK)
WHERE 
    er101_upd_date_iso > DATEADD(month, -1, GETDATE())

-- you can add any index you need on temp table
CREATE INDEX idx_er101_upd_date_iso ON #my_temporary_table(er101_upd_date_iso)

-- run other queries on temporary table (which can be indexed)
SELECT TOP 100
    * 
FROM 
    #my_temporary_table 
ORDER BY 
    er101_upd_date_iso DESC

पेशेवरों:

  • डेटा के किसी भी सबसेट के लिए करना आसान है।
  • प्रबंधन में आसान - यह अस्थायी है और यह तालिका है
  • समग्र प्रणाली के प्रदर्शन को प्रभावित नहीं करता है view
  • अस्थायी तालिका को अनुक्रमित किया जा सकता है।
  • आपको इसकी परवाह नहीं है - यह अस्थायी है :)।

विपक्ष:

  • यह डेटा का स्नैपशॉट है - लेकिन शायद यह अधिकांश तदर्थ प्रश्नों के लिए पर्याप्त है।

2. सामान्य तालिका अभिव्यक्ति - CTE

व्यक्तिगत रूप से मैं विज्ञापन-हॉक प्रश्नों के साथ सीटीई का बहुत उपयोग करता हूं - यह टुकड़ा द्वारा एक क्वेरी टुकड़ा बनाने (और परीक्षण) के साथ बहुत मदद करता है।

नीचे उदाहरण देखें (क्वेरी से शुरू होने वाला WITH)।

पेशेवरों:

  • बड़े दृश्य से शुरुआत करना आसान है और फिर चयन करना और फ़िल्टर करना जो आपको वास्तव में चाहिए।
  • परीक्षण करने में आसान।

विपक्ष:

  • कुछ लोग सीडीई को नापसंद करते हैं - सीडीई प्रश्न लंबे और समझने में मुश्किल लगते हैं।

3. विचार बनाएं

ऊपर जैसा है, लेकिन अस्थायी तालिकाओं के बजाय दृश्य बनाएं (यदि आप अक्सर एक ही क्वेरी के साथ खेलते हैं और आपके पास MS SQL संस्करण है जो अनुक्रमित दृश्यों का समर्थन करता है।

आप जिस डेटा में रुचि रखते हैं और दृश्य पर क्वेरीज़ चला रहे हैं, उस पर विचार या अनुक्रमित दृश्य बना सकते हैं - जिसमें संपूर्ण तालिका की तुलना में डेटा का केवल दिलचस्प सबसेट होना चाहिए।

पेशेवरों:

  • करने में आसान।
  • यह स्रोत डेटा के साथ अद्यतित है।

विपक्ष:

  • केवल डेटा के परिभाषित सबसेट के लिए संभव है।
  • अद्यतनों की उच्च दर वाली बड़ी तालिकाओं के लिए अक्षम हो सकता है।
  • प्रबंधन करना इतना आसान नहीं है।
  • समग्र प्रणाली के प्रदर्शन को प्रभावित कर सकता है।
  • मुझे यकीन नहीं है कि अनुक्रमित विचार एमएस एसक्यूएल के हर संस्करण में उपलब्ध हैं।

सभी स्तंभों का चयन करना

बड़ी टेबल पर रनिंग स्टार क्वेरी ( SELECT * FROM) अच्छी बात नहीं है ...

यदि आपके पास बड़े कॉलम हैं (लंबे तार की तरह) तो उन्हें डिस्क से पढ़ने और नेटवर्क से गुजरने में बहुत समय लगता है।

मैं उन *स्तंभ नामों से प्रतिस्थापित करने का प्रयास करूंगा जिनकी आपको वास्तव में आवश्यकता है।

या, अगर आपको सभी कॉलमों को क्वेरी को फिर से लिखने की कोशिश करनी चाहिए जैसे ( सामान्य डेटा अभिव्यक्ति का उपयोग करके ):

;WITH recs AS (
    SELECT TOP 100 
        id as rec_id -- select primary key only
    FROM 
        er101_acct_order_dtl 
    ORDER BY 
        er101_upd_date_iso DESC
)
SELECT
    er101_acct_order_dtl.*
FROM
    recs
    JOIN
      er101_acct_order_dtl
    ON
      er101_acct_order_dtl.id = recs.rec_id
ORDER BY 
    er101_upd_date_iso DESC 

गंदा पढ़ता है

अंतिम बात जो तदर्थ क्वेरी को गति दे सकती है वह टेबल हिंट केWITH (NOLOCK) साथ गंदे रीड्स की अनुमति दे रही है ।

संकेत के बजाय आप बिना पढ़े लेन-देन के अलगाव स्तर को निर्धारित कर सकते हैं:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

या उचित SQL प्रबंधन स्टूडियो सेटिंग सेट करें।

मुझे लगता है कि तदर्थ प्रश्नों के लिए गंदे रीड काफी अच्छे हैं।


2
+1 के लिए SELECT *- यह SQL सर्वर को क्लस्टर इंडेक्स का उपयोग करने के लिए मजबूर करता है। कम से कम, यह चाहिए। मैं एक गैर-संकुल कवर सूचकांक के लिए कोई वास्तविक कारण नहीं देखता ... पूरी मेज को कवर :)
ta.speot.is

4
यह उत्तर केवल उदाहरण क्वेरी की गति को सुधारने वाले पते को बताता है, प्रश्न को नहीं, जो "तदर्थ प्रश्नों के लिए प्रदर्शन में सुधार करना संभव है"
फिल अप

CDE अब CTE (कॉमन टेबल एक्सप्रेशन) है
sqluser

12

आपको वहां एक टेबल स्कैन मिल रहा है , जिसका अर्थ है कि आपके पास एक इंडेक्स परिभाषित नहीं हैer101_upd_date_iso , या यदि वह कॉलम किसी मौजूदा इंडेक्स का हिस्सा है, तो इंडेक्स का उपयोग नहीं किया जा सकता है (संभवतः यह प्राथमिक इंडेक्सर कॉलम नहीं है)।

अनुपलब्ध अनुक्रमों को जोड़ने से प्रदर्शन को समाप्त करने में मदद मिलेगी।

स्तंभों पर पहले से ही अनुक्रमणिकाएँ होती हैं जिन्हें सबसे अधिक बार देखा जाता है

इसका मतलब यह नहीं है कि वे इस क्वेरी में उपयोग किए जाते हैं (और वे शायद नहीं हैं)।

मेरा सुझाव है कि गेल शॉ, भाग 1 और भाग 2 द्वारा SQL सर्वर में खराब प्रदर्शन के कारणों का पता लगाना ।


मेरी बात यह है कि यह उन कॉलमों में से एक नहीं है जो सबसे अधिक सामान्य रूप से प्रचलित है :)
ली टिकेट

1
@LeeTickett - और फिर भी, यह एकमात्र स्तंभ है जिसे आप संभवतः इस क्वेरी के प्रदर्शन को बेहतर बनाने के लिए एक सूचकांक जोड़ सकते हैं ।
ओड

2
अनुकूलित गैर-अनुक्रमित खोजों जैसी कोई चीज़ नहीं। आप या तो एक सूचकांक, या एक पूर्ण तालिका स्कैन का उपयोग कर रहे हैं। यदि आप पूर्ण तालिका-स्कैन नहीं चाहते हैं, तो आपको अनुक्रमित चाहिए। आपके उपयोग प्रोफ़ाइल के आधार पर, यह केवल अनुक्रमणिका जोड़ने के लिए पर्याप्त सस्ता हो सकता है। ओह, और स्तंभ का डेटा-प्रकार भी मायने रखता है। यदि आपका er101_upd_date_isoएक विशाल संस्करण है, या कोई इंटेंस है, तो प्रदर्शन को सांकेतिक रूप से बदल देगा।
सिलिंड्रिक

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

मैं एक शिक्षार्थी हूं, हमें कैसे पता चलेगा कि किस स्तंभ को अनुक्रमण की आवश्यकता है?
वायरस

7

प्रश्न विशेष रूप से बताता है कि प्रदर्शन को तदर्थ प्रश्नों के लिए सुधारने की आवश्यकता है , और यह कि सूचकांक को जोड़ा नहीं जा सकता है। इसलिए इसे फेस वैल्यू पर लेते हुए, किसी भी टेबल पर प्रदर्शन को बेहतर बनाने के लिए क्या किया जा सकता है?

चूँकि हम तदर्थ प्रश्नों पर विचार कर रहे हैं, इसलिए क्लॉज और ORDER BY क्लॉज में स्तंभों का कोई भी संयोजन हो सकता है। इसका मतलब यह है कि तालिका में कोई भी अनुक्रमणिका रखे जाने के बावजूद, कुछ प्रश्न होंगे जो तालिका स्कैन की आवश्यकता होती है, जैसा कि खराब प्रदर्शन करने वाली क्वेरी के क्वेरी प्लान में ऊपर देखा गया है।

इसे ध्यान में रखते हुए, मान लें कि प्राथमिक कुंजी पर संकुल सूचकांक के अलावा तालिका में कोई अनुक्रमणिका नहीं हैं। अब विचार करते हैं कि प्रदर्शन को अधिकतम करने के लिए हमारे पास क्या विकल्प हैं।

  • तालिका को परिभाषित करें

    जब तक हम एक संकुल अनुक्रमणिका तो हम का उपयोग कर तालिका को Defragment कर सकते हैं बी सी सी INDEXDEFRAG (बहिष्कृत) या अधिमानतः ALTER सूचकांक । इससे तालिका को स्कैन करने के लिए आवश्यक डिस्क रीड की संख्या कम हो जाएगी और गति में सुधार होगा।

  • सबसे तेजी से संभव डिस्क का उपयोग करें। आप यह नहीं कहते कि आप किस डिस्क्स का उपयोग कर रहे हैं, लेकिन यदि आप SSDs का उपयोग कर सकते हैं।

  • टेम्पर्ड बी ऑप्टिमाइज़ करें। सबसे तेजी से संभव डिस्क पर tempdb रखो, फिर से SSDs। इस SO अनुच्छेद और इस RedGate लेख को देखें

  • जैसा कि अन्य उत्तरों में कहा गया है, अधिक चयनात्मक क्वेरी का उपयोग करने से कम डेटा वापस आ जाएगा, और इसलिए तेज होना चाहिए।

अब आइए विचार करें कि यदि हमें अनुक्रमणिका जोड़ने की अनुमति है तो हम क्या कर सकते हैं।

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

  • प्रत्येक कॉलम में सिंगल कॉलम इंडेक्स जोड़ें। यह SQL सर्वर को कम से कम प्रश्नों के बहुमत के लिए गति में सुधार के साथ काम करने के लिए कुछ देना चाहिए, लेकिन इष्टतम नहीं होगा।
  • सबसे सामान्य प्रश्नों के लिए विशिष्ट अनुक्रमणिकाएं जोड़ें ताकि वे अनुकूलित हों।
  • खराब प्रदर्शन करने वाले प्रश्नों की निगरानी के लिए आवश्यकतानुसार अतिरिक्त विशिष्ट सूचकांक जोड़ें।

संपादित करें

मैंने 22 मिलियन पंक्तियों के 'बड़े' टेबल पर कुछ परीक्षण चलाए हैं। मेरी तालिका में केवल छह कॉलम हैं लेकिन इसमें 4GB डेटा है। मेरी मशीन एक सम्मानजनक डेस्कटॉप है जिसमें 8 जीबी रैम और एक क्वाड कोर सीपीयू है और एक एकल चपलता 3 एसएसडी है।

मैंने आईडी कॉलम पर प्राथमिक कुंजी के अलावा सभी अनुक्रमित हटा दिए।

यदि प्रश्न में दी गई समस्या की एक समान क्वेरी को 5 सेकंड लगते हैं यदि SQL सर्वर पहले और 3 सेकंड बाद पुनः आरंभ होता है। डेटाबेस ट्यूनिंग सलाहकार स्पष्ट रूप से> 99% के अनुमानित सुधार के साथ, इस क्वेरी को सुधारने के लिए एक सूचकांक जोड़ने की सलाह देता है। प्रभावी रूप से शून्य के क्वेरी समय में एक इंडेक्स परिणाम जोड़ना।

यह भी दिलचस्प है कि मेरी क्वेरी योजना आपके (क्लस्टर इंडेक्स स्कैन के साथ) समान है, लेकिन इंडेक्स स्कैन में क्वेरी लागत का 9% और शेष 91% सॉर्ट होता है। मैं केवल यह मान सकता हूं कि आपकी तालिका में डेटा की एक विशाल मात्रा है और / या आपके डिस्क बहुत धीमे हैं या बहुत धीमे नेटवर्क कनेक्शन पर स्थित हैं।


2

यहां तक ​​कि अगर आपके पास कुछ प्रश्नों में उपयोग किए जाने वाले कुछ स्तंभों पर अनुक्रमित हैं, तो यह तथ्य कि आपकी 'तदर्थ' क्वेरी एक टेबल स्कैन का कारण बनती है, आपके पास इस क्वेरी को कुशलता से पूरा करने की अनुमति देने के लिए पर्याप्त अनुक्रमित नहीं हैं।

विशेष रूप से तिथि सीमाओं के लिए अच्छे सूचकांक जोड़ना मुश्किल है।

बस आपकी क्वेरी को देखते हुए, db को पहले n रिकॉर्ड्स को वापस करने में सक्षम होने के लिए चयनित कॉलम द्वारा सभी रिकॉर्ड को सॉर्ट करना होगा।

क्या db भी क्लॉज द्वारा ऑर्डर के बिना फुल टेबल स्कैन करता है? क्या तालिका में एक प्राथमिक कुंजी है - पीके के बिना, डीबी को सॉर्ट करने के लिए कड़ी मेहनत करनी होगी?


मेज पर एक प्राथमिक कुंजी है। निष्पादन योजना में एक टेबल स्कैन भी दिखाई देता है जब बस क्रियान्वित होता हैselect top 100 * from ER101_ACCT_ORDER_DTL
ली टिकेट

2

यह कैसे संभव है? Er101_upd_date_iso कॉलम पर एक इंडेक्स के बिना क्लस्टर इंडेक्स स्कैन का उपयोग कैसे किया जा सकता है?

एक सूचकांक एक बी-ट्री है जहां प्रत्येक पत्ती का नोड 'पंक्तियों का एक गुच्छा' (एसक्यूएल आंतरिक शब्दावली में 'पेज' कहा जाता है) की ओर इशारा करता है, वह यह है कि जब सूचकांक एक गैर-क्लस्टर सूचकांक है।

गुच्छेदार सूचकांक एक विशेष मामला है, जिसमें पत्ती नोड्स में 'पंक्तियों का गुच्छा' है (बजाय उन्हें इंगित करने के)। इसीलिए...

1) मेज पर केवल एक संकुल सूचकांक हो सकता है।

इसका अर्थ यह भी है कि पूरी तालिका को संकुल सूचकांक के रूप में संग्रहीत किया जाता है, यही कारण है कि आपने तालिका स्कैन के बजाय सूचकांक स्कैन देखना शुरू किया।

2) क्लस्टर्ड इंडेक्स का उपयोग करने वाला एक ऑपरेशन आम तौर पर एक गैर-क्लस्टर इंडेक्स की तुलना में तेज होता है

Http://msdn.microsoft.com/en-us/library/ms177443.aspx पर और पढ़ें

आपके पास जो समस्या है, उसके लिए आपको वास्तव में इस कॉलम को एक इंडेक्स में जोड़ने पर विचार करना चाहिए, जैसा कि आपने कहा कि एक नया इंडेक्स (या किसी मौजूदा इंडेक्स पर एक कॉलम) जोड़ने से INSERT / UPDATE लागत बढ़ जाती है। लेकिन 'er101_upd_date_iso' के साथ बदलने के लिए कुछ कम किए गए अनुक्रमणिका (या किसी मौजूदा सूचकांक से एक स्तंभ) को निकालना संभव हो सकता है।

यदि अनुक्रमणिका परिवर्तन संभव नहीं है, तो मैं स्तंभ पर एक आँकड़े जोड़ने की सलाह देता हूं, यह उन चीज़ों को तेज़ कर सकता है जब स्तंभों में अनुक्रमित स्तंभों के साथ कुछ संबंध है

http://msdn.microsoft.com/en-us/library/ms188038.aspx

यदि आप ER101_ACCT_ORDER_DTL की तालिका स्कीमा पोस्ट कर सकते हैं, तो BTW, आपको बहुत अधिक सहायता मिलेगी। और मौजूदा सूचकांक भी ..., शायद उनमें से कुछ का उपयोग करने के लिए क्वेरी फिर से लिखी जा सकती है।


जवाब के लिए +1। एक टिप्पणी हालांकि, क्लस्टर किए गए इंडेक्स हमेशा तेज़ नहीं होते हैं क्योंकि कोई भी आपके उत्तर से पढ़ सकता है (इसे गलत समझना संभव है)।
गिस्ली

मुझे लगता है कि मैं क्लस्टर्ड / नॉन-क्लस्टर्ड इंडेक्स के बीच अंतर को समझता हूं, लेकिन फिर भी यह नहीं देखता कि किसी कॉलम को क्वेरी करना, जो क्लस्टर इंडेक्स का हिस्सा नहीं है, अन्य कॉलम पर क्लस्टर इंडेक्स होने से कैसे सुधार किया जा सकता है?
ली टिकेट

SQL सर्वर में क्लस्टर किए गए अनुक्रमणिका में सभी कॉलम होते हैं। क्लस्टर इंडेक्स वह है जो यह तय करता है कि डिस्क पर डेटा कैसे संग्रहीत किया जाता है। मेरे लिए इसे समझाना थोड़ा कठिन है, लेकिन अगर आप इंडेक्स को एक पेड़ के रूप में समझते हैं, तो अस्पष्ट इंडेक्स एक पेड़ है और नीचे की पत्तियों में वह जानकारी होती है, जिसे आपने इंडेक्स के रूप में परिभाषित किया था। एक संकुल सूचकांक के लिए, नीचे की पत्तियों में तालिका के सभी कॉलम होते हैं। यह SQL Server में डिज़ाइन द्वारा है।
गिस्ली

मै समझ गया। लेकिन मुझे लगा कि शाखाएँ गुच्छित सूचकांक में स्तंभों पर आधारित थीं। इसलिए यदि कॉलम मैं क्वेरी नहीं कर रहा हूं तो वह निश्चित रूप से अनुक्रमित नहीं है, तो निश्चित रूप से हर शाखा / पत्ते को स्कैन करने की आवश्यकता है?
ली टिकेट

1
मुझे यह नहीं मिलता। मेरा सबसे अच्छा अनुमान है कि जब आपके पास एक अस्पष्ट सूचकांक था, तो इसे स्कैन किया गया था जिसके परिणामस्वरूप बहुत सारे यादृच्छिक I / O थे। जब आपने क्लस्टर इंडेक्स बनाया तो आपको उन यादृच्छिक I / O से छुटकारा मिल गया? लेकिन यह एक अनुमान है, मुझे इस व्यवहार का कोई अन्य कारण नहीं मिल रहा है लेकिन मैं कोई विशेषज्ञ नहीं हूं।
गिस्ली

1

आपके 1M परीक्षण के जल्दी चलने के कारणों में से एक संभावना है क्योंकि अस्थायी टेबल पूरी तरह से मेमोरी में हैं और केवल डिस्क पर जाएंगे यदि आपका सर्वर मेमोरी दबाव का अनुभव करता है। आप या तो ऑर्डर को हटाने के लिए अपनी क्वेरी को फिर से तैयार कर सकते हैं, पहले से बताए अनुसार एक अच्छा क्लस्टर इंडेक्स और कवरिंग इंडेक्स (एस) जोड़ सकते हैं, या डीएमवी को क्वेरी कर सकते हैं कि क्या हार्डवेयर संबंधित देखने के लिए।

-- From Glen Barry
-- Clear Wait Stats (consider clearing and running wait stats query again after a few minutes)
-- DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR);

-- Check Task Counts to get an initial idea what the problem might be

-- Avg Current Tasks Count, Avg Runnable Tasks Count, Avg Pending Disk IO Count across all schedulers
-- Run several times in quick succession
SELECT AVG(current_tasks_count) AS [Avg Task Count], 
       AVG(runnable_tasks_count) AS [Avg Runnable Task Count],
       AVG(pending_disk_io_count) AS [Avg Pending DiskIO Count]
FROM sys.dm_os_schedulers WITH (NOLOCK)
WHERE scheduler_id < 255 OPTION (RECOMPILE);

-- Sustained values above 10 suggest further investigation in that area
-- High current_tasks_count is often an indication of locking/blocking problems
-- High runnable_tasks_count is a good indication of CPU pressure
-- High pending_disk_io_count is an indication of I/O pressure

मुझे आशा है कि मेरा पूरा डेटाबेस मेमोरी में होगा। वहाँ एक तरीका है कि जाँच करने के लिए या sql जो तालिकाओं को स्मृति में संग्रहीत करने के लिए है? मैं कुछ दिनों के लिए दूर हो गया, लेकिन जब मैं वापस आऊंगा तो मैं आपकी
क्वेरी की

औसत टास्क काउंट और ग्राउंड पेंडिंग डिसियो काउंट 4. पर चरम पर है, मैं अभी भी राम में db को मजबूर करने के बारे में उत्सुक हूं।
ली टिकेट

0

मुझे पता है कि आपने कहा था कि इंडेक्स जोड़ना कोई विकल्प नहीं है, लेकिन आपके पास टेबल स्कैन को खत्म करने का एकमात्र विकल्प होगा। जब आप एक स्कैन करते हैं, तो SQL सर्वर आपकी क्वेरी को पूरा करने के लिए टेबल पर सभी 2 मिलियन पंक्तियों को पढ़ता है।

यह लेख अधिक जानकारी प्रदान करता है लेकिन याद रखें: सीक = अच्छा, स्कैन = बुरा।

दूसरा, क्या आप चयनित * को समाप्त नहीं कर सकते हैं और केवल उन कॉलम का चयन कर सकते हैं जिनकी आपको आवश्यकता है? तीसरा, कोई "कहाँ" खंड? यहां तक ​​कि अगर आपके पास एक सूचकांक है, क्योंकि आप सब कुछ पढ़ रहे हैं जो आपको सबसे अच्छा मिलेगा, एक सूचकांक स्कैन है (जो टेबल स्कैन से बेहतर है, लेकिन यह एक तलाश नहीं है, जिसे आपको लक्ष्य बनाना चाहिए)


यह सच नहीं है कि सीक हमेशा स्कैन से बेहतर है। कभी-कभी एक स्कैन वास्तव में अधिक कुशल होता है। यदि यह मामला नहीं था, तो M $ में SQL Server 2008 R2 में शुरू होने वाले FORCESCAN क्वेरी संकेत शामिल नहीं होंगे। अधिक जानकारी के लिए यहां देखें: msdn.microsoft.com/en-us/library/ms181714(v=sql.105).aspx और यहां तक ​​कि किसी को स्कैन करने के लिए मजबूर करने वाले व्यक्ति के लिए (एडम हेंस द्वारा तीसरा उत्तर अच्छी जानकारी है: सामाजिक .msdn.microsoft.com / Forums / en-US / transactsql / thread /…
सोलोमन रटज़की

1
खैर, सबसे पहले, पॉइंट-जैसे प्रश्नों के लिए सीकस अच्छे हैं। दूसरा, स्कैन रेंज क्वेश्चन के लिए अच्छे होते हैं, जहाँ बहुत सारे डेटा को पुनः प्राप्त किया जाना चाहिए। OLAP सिस्टम स्कैन के बिना अच्छा प्रदर्शन नहीं करेगा। ओएलटीपी सिस्टम बिना प्रक्षेपास्त्रों के अच्छा प्रदर्शन नहीं करेगा। चीजों की भव्य योजना में हर चीज का अपना स्थान है ...
darlove

0

मुझे पता है कि यह शुरुआत से काफी समय रहा है ... इन सभी उत्तरों में बहुत ज्ञान है। क्वेरी को बेहतर बनाने का प्रयास करते समय अच्छी अनुक्रमणिका पहली चीज है। खैर, लगभग पहले। सबसे पहले (बोलने के लिए) कोड में बदलाव कर रहा है ताकि यह कुशल हो। इसलिए, सभी के कहने और किए जाने के बाद, यदि किसी के पास कोई प्रश्न नहीं है, जहां या जहां WHERE- स्थिति पर्याप्त नहीं है, तो डेटा प्राप्त करने का केवल एक ही तरीका है: टेबल स्कैन (INDEX SCAN)। यदि किसी को तालिका से सभी कॉलमों की आवश्यकता है, तो टेबल स्कैन का उपयोग किया जाएगा - इसके बारे में कोई सवाल नहीं। यह डेटा संगठन के प्रकार के आधार पर एक ढेर स्कैन या क्लस्टर इंडेक्स स्कैन हो सकता है। चीजों को गति देने का एकमात्र अंतिम तरीका (यदि संभव हो तो), यह सुनिश्चित करना है कि स्कैन करने के लिए यथासंभव कोर का उपयोग किया जाता है: विकल्प (मैक्सडॉप 0)। मैं भंडारण के विषय की अनदेखी कर रहा हूँ, निश्चित रूप से,

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.