ปรับปรุงประสิทธิภาพการสืบค้น SQL Server บนตารางขนาดใหญ่


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.

เซิร์ฟเวอร์ค่อนข้างมีประสิทธิภาพ (จากหน่วยความจำ 48GB ram, โปรเซสเซอร์ 24 คอร์) ที่รัน sql server 2008 r2 x64

อัปเดต

ฉันพบรหัสนี้เพื่อสร้างตารางที่มีข้อมูล 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;

แต่ในเซิร์ฟเวอร์ทดสอบทั้งสามเครื่องจะมีการเรียกใช้แบบสอบถามเกือบจะทันที ใครช่วยอธิบายเรื่องนี้

ใส่คำอธิบายภาพที่นี่

อัปเดต 2

ขอบคุณสำหรับความคิดเห็น - โปรดให้พวกเขามา ... พวกเขาทำให้ฉันลองเปลี่ยนดัชนีคีย์หลักจากที่ไม่ใช่คลัสเตอร์เป็นคลัสเตอร์ด้วยผลลัพธ์ที่ค่อนข้างน่าสนใจ (และไม่คาดคิด?)

ไม่ใช่คลัสเตอร์:

ใส่คำอธิบายภาพที่นี่

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 จะใช้การสแกนดัชนีคลัสเตอร์ได้อย่างไร

อัปเดต 3

ตามที่ร้องขอ - นี่คือสคริปต์สร้างตาราง:

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 GB โดยขนาดดัชนีอยู่ที่ 3.9 GB


1
มีคำแนะนำเล็กน้อยเมื่อคุณวางเคอร์เซอร์เมาส์เหนือรายการแผน แสดงค่า I / O และ CPU โดยประมาณ ฉันจะดูแลเกี่ยวกับต้นทุน I / O ในตอนแรก
Grzegorz Gierlik

4
Table Scanหมายถึงฮีป (ไม่มีดัชนีคลัสเตอร์) ดังนั้นขั้นตอนแรกคือการเพิ่มดัชนีคลัสเตอร์ที่ดีและรวดเร็วลงในตารางของคุณ ขั้นตอนที่สองอาจเป็นการตรวจสอบว่าดัชนีที่ไม่เป็นคลัสเตอร์er101_upd_date_isoจะช่วยได้หรือไม่ (และไม่ก่อให้เกิดข้อเสียด้านประสิทธิภาพอื่น ๆ )
marc_s

1
@marc_s ขอบคุณสำหรับสิ่งนั้น - ฉันเปลี่ยนดัชนี pk เป็นคลัสเตอร์และได้สร้างความแตกต่างทางการเงินคุณสามารถอธิบายสิ่งนี้เพิ่มเติมได้หรือไม่ (ดูอัปเดต 2)
Lee Tickett

2
ดัชนีคลัสเตอร์เพียงแค่เปลี่ยนรูปแบบการจัดเก็บของตาราง ดัชนีคลัสเตอร์ประกอบด้วยข้อมูลตารางจริงในโหนดระดับใบไม้นั่นคือเพื่ออ่านทั้งตารางขณะนี้ SQL Server กำลังทำการสแกนดัชนีคลัสเตอร์ (โดยทั่วไปคือ "การสแกนตาราง" บนตารางที่มีดัชนีคลัสเตอร์) นั่นมักจะเร็วกว่าการสแกนตารางบนฮีป (โดยไม่มีดัชนีคลัสเตอร์) หากคุณเพิ่มดัชนีที่ไม่เป็นคลัสเตอร์ในer101_upd_date_isoคอลัมน์ในตอนนี้คุณยังสามารถกำจัดการดำเนินการ "จัดเรียง" ในแผนการดำเนินการของคุณและเพิ่มความเร็วให้มากขึ้นได้
marc_s

2
@LeeTickett โปรดแสดงนิยามตารางและดัชนีของคุณ มีหลายปัจจัยที่ต้องพิจารณาและดูเหมือนจะไม่มีใครถามถึงสิ่งเหล่านี้ (ซึ่งทำให้ฉันประหลาดใจ แต่ก็ไม่ควรทำ) ฉันบอกคุณได้ว่า 2 ล้านแถวนั้นไม่ใหญ่และตารางที่จัดทำดัชนีไว้อย่างถูกต้องโดย 200 ล้านแถวจะกลับมาเร็วกว่านี้ เป็นไปได้มากว่าดัชนีคลัสเตอร์ (ตอนนี้คุณมีแล้วขอบคุณ marc_s) เป็นตัวเลือกที่ไม่ดี แต่พูดยากโดยไม่เห็นเฉพาะ อย่าใช้การแบ่งพาร์ติชัน แต่ใช้ SET STATISTICS IO ON และตรวจสอบ Logical Reads ในแท็บข้อความ หากการเปลี่ยนแปลงลดการอ่านเชิงตรรกะคุณจะเข้าใกล้
Solomon Rutzky

คำตอบ:


59

คำตอบง่ายๆ: ไม่ คุณไม่สามารถช่วยค้นหาแบบเฉพาะกิจในตารางคอลัมน์ 238 ที่มี Fill Factor 50% ในดัชนีคลัสเตอร์

คำตอบโดยละเอียด:

ดังที่ฉันได้ระบุไว้ในคำตอบอื่น ๆ ในหัวข้อนี้การออกแบบดัชนีเป็นทั้งศิลปะและวิทยาศาสตร์และมีหลายปัจจัยที่ต้องพิจารณาว่ามีกฎที่ยากและรวดเร็วน้อยมากถ้ามี คุณต้องพิจารณา: ปริมาณของการดำเนินการ DML เทียบกับ SELECT ระบบย่อยของดิสก์ดัชนี / ทริกเกอร์อื่น ๆ บนตารางการกระจายข้อมูลภายในตารางเป็นการสืบค้นโดยใช้เงื่อนไข SARGable WHERE และสิ่งอื่น ๆ อีกมากมายที่ฉันจำไม่ได้ ตอนนี้.

ฉันสามารถพูดได้ว่าไม่สามารถให้ความช่วยเหลือใด ๆ สำหรับคำถามในหัวข้อนี้หากปราศจากความเข้าใจเกี่ยวกับตารางดัชนีทริกเกอร์และอื่น ๆ ตอนนี้คุณได้โพสต์คำจำกัดความของตารางแล้ว (ยังคงรอดัชนี แต่นิยามตารางเพียงอย่างเดียวชี้ไปที่ 99% ของปัญหา) ฉันสามารถเสนอคำแนะนำได้

ขั้นแรกถ้าคำจำกัดความของตารางถูกต้อง (238 คอลัมน์, 50% Fill Factor) คุณก็สามารถเพิกเฉยต่อคำตอบ / คำแนะนำที่เหลือได้ที่นี่ ;-) ขออภัยที่พูดน้อยกว่าการเมืองที่นี่ แต่ที่จริงจังคือการไล่ล่าห่านป่าโดยไม่ทราบรายละเอียดเฉพาะ และตอนนี้เราเห็นคำจำกัดความของตารางแล้วมันก็ค่อนข้างชัดเจนขึ้นว่าทำไมคิวรีธรรมดาถึงใช้เวลานานขนาดนี้ทั้งๆที่คิวรีทดสอบ (อัพเดท # 1) ทำงานเร็วมาก

ปัญหาหลักที่นี่ (และในสถานการณ์ที่มีประสิทธิภาพต่ำ) คือการสร้างแบบจำลองข้อมูลที่ไม่ดี 238 คอลัมน์ไม่ได้ห้ามเช่นเดียวกับการมี 999 ดัชนีไม่ได้รับอนุญาต แต่โดยทั่วไปแล้วก็ไม่ฉลาดเช่นกัน

คำแนะนำ:

  1. อันดับแรกตารางนี้ต้องได้รับการออกแบบใหม่จริงๆ ถ้านี่เป็นตารางคลังข้อมูลอาจจะ แต่ถ้าไม่ใช่แล้วฟิลด์เหล่านี้จำเป็นต้องแบ่งออกเป็นหลาย ๆ ตารางซึ่งสามารถมี PK เดียวกัน คุณจะมีตารางบันทึกหลักและตารางย่อยเป็นเพียงข้อมูลที่ขึ้นอยู่กับคุณสมบัติที่เกี่ยวข้องโดยทั่วไปและ PK ของตารางเหล่านั้นจะเหมือนกับ PK ของตารางหลักและด้วยเหตุนี้ FK ไปยังตารางหลักด้วย จะมีความสัมพันธ์แบบ 1 ต่อ 1 ระหว่างตารางหลักและตารางรองทั้งหมด
  2. การใช้งานANSI_PADDING OFFเป็นการรบกวนไม่ต้องพูดถึงความไม่สอดคล้องกันภายในตารางเนื่องจากการเพิ่มคอลัมน์ต่างๆเมื่อเวลาผ่านไป ไม่แน่ใจว่าตอนนี้คุณสามารถแก้ไขได้หรือไม่ แต่คุณควรมีเสมอANSI_PADDING ONหรืออย่างน้อยที่สุดก็มีการตั้งค่าเดียวกันในทุกALTER TABLEคำสั่ง
  3. พิจารณาสร้างกลุ่มไฟล์เพิ่มเติม 2 กลุ่ม ได้แก่ ตารางและดัชนี ที่ดีที่สุดคืออย่าใส่ข้อมูลของคุณลงไปในPRIMARYขณะที่ SQL SERVER เก็บข้อมูลและข้อมูลเมตาทั้งหมดเกี่ยวกับวัตถุของคุณ คุณสร้างตารางและดัชนีคลัสเตอร์ของคุณ (ตามที่เป็นข้อมูลสำหรับตาราง) [Tables]และดัชนีที่ไม่ใช่คลัสเตอร์ทั้งหมดบน[Indexes]
  4. เพิ่ม Fill Factor จาก 50% ตัวเลขที่ต่ำนี้น่าจะเป็นสาเหตุที่พื้นที่ดัชนีของคุณมีขนาดใหญ่กว่าพื้นที่ข้อมูลของคุณ การสร้างดัชนีใหม่จะสร้างหน้าข้อมูลขึ้นมาใหม่โดยมีขนาดสูงสุด 4k (จากขนาดหน้าทั้งหมด 8k) ที่ใช้สำหรับข้อมูลของคุณเพื่อให้ตารางของคุณกระจายออกไปในพื้นที่กว้าง
  5. หากข้อความค้นหาส่วนใหญ่หรือทั้งหมดมี "ER101_ORG_CODE" อยู่ในWHEREเงื่อนไขให้พิจารณาย้ายไปที่คอลัมน์นำหน้าของดัชนีคลัสเตอร์ สมมติว่ามีการใช้บ่อยกว่า "ER101_ORD_NBR" หากใช้ "ER101_ORD_NBR" บ่อยขึ้นให้เก็บไว้ ดูเหมือนว่าสมมติว่าชื่อฟิลด์หมายถึง "OrganizationCode" และ "OrderNumber" นั่นคือ "OrgCode" เป็นการจัดกลุ่มที่ดีกว่าซึ่งอาจมี "OrderNumbers" หลายรายการอยู่ภายใน
  6. จุดรอง แต่ถ้า "ER101_ORG_CODE" เป็น 2 อักขระเสมอให้ใช้CHAR(2)แทนVARCHAR(2)เนื่องจากจะบันทึกไบต์ในส่วนหัวของแถวซึ่งติดตามขนาดความกว้างของตัวแปรและเพิ่มขึ้นเป็นล้านแถว
  7. ดังที่คนอื่น ๆ กล่าวถึงการใช้SELECT *จะส่งผลเสียต่อประสิทธิภาพ ไม่เพียง แต่เนื่องจากต้องใช้ SQL Server เพื่อส่งคืนคอลัมน์ทั้งหมดและด้วยเหตุนี้จึงมีแนวโน้มที่จะทำการสแกนดัชนีคลัสเตอร์โดยไม่คำนึงถึงดัชนีอื่น ๆ ของคุณ แต่ยังต้องใช้เวลา SQL Server ในการไปที่นิยามตารางและแปล*เป็นชื่อคอลัมน์ทั้งหมด . ควรจะเร็วกว่าเล็กน้อยในการระบุชื่อคอลัมน์ 238 ทั้งหมดในSELECTรายการแม้ว่าจะไม่ช่วยปัญหาการสแกน แต่คุณต้องการทั้งหมด 238 คอลัมน์ในเวลาเดียวกันหรือไม่?

โชคดี!

อัปเดต
เพื่อความสมบูรณ์ของคำถาม "วิธีการปรับปรุงประสิทธิภาพบนตารางขนาดใหญ่สำหรับการสืบค้นแบบเฉพาะกิจ" ควรสังเกตว่าแม้ว่าจะไม่ช่วยในกรณีนี้หากมีคนใช้ SQL Server 2012 (หรือใหม่กว่า เมื่อถึงเวลานั้น) และหากตารางไม่ได้รับการอัปเดตให้ใช้ Columnstore Indexes เป็นตัวเลือก สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับคุณลักษณะใหม่นั้นโปรดดูที่นี่: http://msdn.microsoft.com/en-us/library/gg492088.aspx (ฉันเชื่อว่าสิ่งเหล่านี้ถูกทำให้สามารถอัปเดตได้โดยเริ่มใน SQL Server 2014)

UPDATE 2
สิ่งที่ต้องพิจารณาเพิ่มเติม ได้แก่ :

  • เปิดใช้งานการบีบอัดบนดัชนีคลัสเตอร์ ตัวเลือกนี้พร้อมใช้งานใน SQL Server 2008 แต่เป็นคุณลักษณะเฉพาะของ Enterprise Edition อย่างไรก็ตามใน SQL Server 2016 SP1การบีบอัดข้อมูลพร้อมใช้งานในทุกรุ่น ! โปรดดูหน้า MSDN สำหรับการบีบอัดข้อมูลสำหรับรายละเอียดเกี่ยวกับการบีบอัดแถวและหน้า
  • ถ้าคุณไม่สามารถใช้การบีบอัดข้อมูลหรือถ้ามันจะไม่ให้ประโยชน์มากสำหรับตารางโดยเฉพาะอย่างยิ่งแล้วถ้าคุณมีคอลัมน์ประเภทคงที่ยาว ( INT, BIGINT, TINYINT, SMALLINT, CHAR, NCHAR, BINARY, DATETIME, SMALLDATETIME, MONEY, ฯลฯ ) และดีกว่า 50 % ของแถวNULLแล้วพิจารณาเปิดใช้งานSPARSEตัวเลือกที่พร้อมใช้งานใน SQL Server 2008 โปรดดูรายละเอียดในหน้า MSDN สำหรับUse Sparse Columns

ในจุดที่ 7 โดยส่วนตัวฉันคิดว่าควรจะเพิ่มชื่อคอลัมน์ 238 ชื่อจากข้อมูลเมตาได้เร็วกว่าการแยกวิเคราะห์ออกจากข้อความค้นหาจากนั้นต้องตรวจสอบข้อมูลเมตาต่อไปเพื่อให้แน่ใจว่ามีอยู่ทั้งหมดมีข้อโต้แย้งที่หนักแน่นเพียงพอที่จะต่อต้าน*โดยไม่มีข้อพิรุธนั้น
Martin Smith

54

มีปัญหาบางประการเกี่ยวกับคำค้นหานี้ (และใช้กับทุกการสืบค้น)

ขาดดัชนี

การขาดดัชนีในer101_upd_date_isoคอลัมน์เป็นสิ่งที่สำคัญที่สุดตามที่Odedได้กล่าวไว้แล้ว

หากไม่มีดัชนีที่ตรงกัน (ซึ่งการขาดอาจทำให้เกิดการสแกนตาราง) จะไม่มีโอกาสเรียกใช้การสืบค้นด่วนบนตารางขนาดใหญ่

หากคุณไม่สามารถเพิ่มดัชนีได้ (ด้วยเหตุผลหลายประการรวมถึงไม่มีประเด็นในการสร้างดัชนีสำหรับแบบสอบถามเฉพาะกิจเพียงรายการเดียว ) ฉันขอแนะนำวิธีแก้ปัญหาบางประการ (ซึ่งสามารถใช้สำหรับการสืบค้นแบบเฉพาะกิจ):

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

โดยส่วนตัวแล้วฉันใช้CTEเป็นจำนวนมากกับแบบสอบถามเฉพาะกิจ - มันช่วยได้มากในการสร้าง (และทดสอบ) แบบสอบถามทีละชิ้น

ดูตัวอย่างด้านล่าง (ข้อความค้นหาเริ่มต้นด้วยWITH)

ข้อดี:

  • สร้างได้ง่ายโดยเริ่มจากมุมมองขนาดใหญ่จากนั้นเลือกและกรองสิ่งที่คุณต้องการจริงๆ
  • ง่ายต่อการทดสอบ

จุดด้อย:

  • บางคนไม่ชอบคำถาม CDE - คำถาม CDE ดูเหมือนจะยาวและเข้าใจยาก

3. สร้างมุมมอง

คล้ายกับด้านบน แต่สร้างมุมมองแทนตารางชั่วคราว (หากคุณเล่นบ่อยๆด้วยแบบสอบถามเดียวกันและคุณมีเวอร์ชัน MS SQL ที่รองรับมุมมองที่จัดทำดัชนี

คุณสามารถสร้างมุมมองหรือมุมมองที่จัดทำดัชนีในชุดข้อมูลย่อยที่คุณสนใจและเรียกใช้การสืบค้นในมุมมองซึ่งควรมีเฉพาะข้อมูลย่อยที่น่าสนใจซึ่งมีขนาดเล็กกว่าทั้งตารางมาก

ข้อดี:

  • ง่ายต่อการทำ
  • เป็นข้อมูลล่าสุดของแหล่งข้อมูล

จุดด้อย:

  • เป็นไปได้สำหรับชุดข้อมูลย่อยที่กำหนดไว้เท่านั้น
  • อาจไม่มีประสิทธิภาพสำหรับตารางขนาดใหญ่ที่มีอัตราการอัปเดตสูง
  • ไม่ใช่เรื่องง่ายที่จะจัดการ
  • อาจส่งผลต่อประสิทธิภาพของระบบโดยรวม
  • ฉันไม่แน่ใจว่ามุมมองที่จัดทำดัชนีมีอยู่ใน MS SQL ทุกเวอร์ชัน

การเลือกคอลัมน์ทั้งหมด

การเรียกใช้star query ( 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 Management Studio ที่เหมาะสม

ฉันคิดว่าสำหรับการค้นหาเฉพาะกิจการอ่านสกปรกนั้นดีพอ


2
+1 สำหรับSELECT *- บังคับให้ SQL Server ใช้ดัชนีคลัสเตอร์ อย่างน้อยก็ควร ฉันไม่เห็นเหตุผลที่แท้จริงสำหรับดัชนีการครอบคลุมที่ไม่ใช่คลัสเตอร์ ... ครอบคลุมทั้งตาราง :)
ta.speot.is

4
คำตอบนี้กล่าวถึงการปรับปรุงความเร็วของข้อความค้นหาตัวอย่างเท่านั้นไม่ใช่คำถามซึ่งก็คือ "เป็นไปได้หรือไม่ที่จะปรับปรุงประสิทธิภาพสำหรับข้อความค้นหาเฉพาะกิจ"
Phil

CDE ตอนนี้คือ CTE (Common Table Expression)
sqluser

12

คุณกำลังได้รับการสแกนตารางที่นั่นหมายความว่าคุณไม่มีดัชนีที่กำหนดไว้er101_upd_date_isoหรือถ้าคอลัมน์นั้นเป็นส่วนหนึ่งของดัชนีที่มีอยู่ก็จะไม่สามารถใช้ดัชนีได้ (อาจไม่ใช่คอลัมน์ตัวทำดัชนีหลัก)

การเพิ่มดัชนีที่ขาดหายไปจะช่วยให้ประสิทธิภาพไม่สิ้นสุด

มีดัชนีอยู่แล้วในคอลัมน์ที่มีการสืบค้นมากที่สุด

นั่นไม่ได้หมายความว่ามีการใช้คำค้นหานี้ (และอาจไม่ใช่)

ผมขอแนะนำให้อ่านหาสาเหตุของการเกิดประสิทธิภาพที่ดีใน SQL Server โดยเกลชอว์ส่วนที่ 1และส่วนที่ 2


ประเด็นของฉันคือนี่ไม่ใช่หนึ่งในคอลัมน์ที่ถูกถามบ่อยที่สุด :)
Lee Tickett

1
@LeeTickett - แต่นี่เป็นคอลัมน์เดียวที่คุณสามารถเพิ่มดัชนีเพื่อปรับปรุงประสิทธิภาพของแบบสอบถามนี้ได้
Oded

2
ไม่มีสิ่งที่เรียกว่าการค้นหาที่ไม่มีการจัดทำดัชนีที่เหมาะสม คุณกำลังใช้ดัชนีหรือการสแกนแบบเต็มตาราง หากคุณไม่ต้องการการสแกนแบบเต็มตารางคุณต้องมีดัชนี ขึ้นอยู่กับโปรไฟล์การใช้งานของคุณอาจมีราคาถูกพอที่จะเพิ่มดัชนี อ้อและประเภทข้อมูลของคอลัมน์ก็มีความสำคัญเช่นกัน หากคุณer101_upd_date_isoเป็น varchar ขนาดใหญ่หรือ int จะเปลี่ยนประสิทธิภาพอย่างมีนัยสำคัญ
Cylindric

ขอบคุณ. ฉันได้เพิ่มความคิดเห็นในคำถามแล้ว ฉันขอขอบคุณที่ไม่น่าจะเพิ่มประสิทธิภาพการสืบค้นได้ แต่ฉันคิดว่าอาจมีหลายวิธีที่ฉันสามารถปรับปรุงประสิทธิภาพของข้อความค้นหาแบบเฉพาะกิจได้
Lee Tickett

ฉันเป็นผู้เรียนรู้ได้อย่างไรว่าคอลัมน์ใดต้องการการจัดทำดัชนี
ไวรัส

7

คำถามระบุเฉพาะประสิทธิภาพที่ต้องได้รับการปรับปรุงสำหรับคำค้นหาเฉพาะกิจและไม่สามารถเพิ่มดัชนีได้ ดังนั้นการพิจารณาตามมูลค่าที่ตราไว้สิ่งที่สามารถทำได้เพื่อปรับปรุงประสิทธิภาพในตารางใด ๆ

เนื่องจากเรากำลังพิจารณาข้อความค้นหาเฉพาะกิจ WHERE clause และ ORDER BY clause สามารถมีคอลัมน์ผสมกันได้ ซึ่งหมายความว่าเกือบจะไม่ว่าดัชนีใดที่วางไว้บนตารางจะมีคำค้นหาบางอย่างที่ต้องใช้การสแกนตารางดังที่เห็นด้านบนในแผนการสืบค้นของแบบสอบถามที่มีประสิทธิภาพต่ำ

เมื่อพิจารณาถึงสิ่งนี้สมมติว่าไม่มีดัชนีใด ๆ เลยบนโต๊ะนอกเหนือจากดัชนีคลัสเตอร์บนคีย์หลัก ตอนนี้เรามาพิจารณาตัวเลือกที่เรามีเพื่อเพิ่มประสิทธิภาพสูงสุด

  • จัดเรียงข้อมูลในตาราง

    ตราบใดที่เรามีดัชนีคลัสเตอร์แล้วเราสามารถจัดระเบียบตารางโดยใช้DBCC INDEXDEFRAG (เลิกใช้) หรือเด่นALTER INDEX วิธีนี้จะลดจำนวนการอ่านดิสก์ที่ต้องใช้ในการสแกนตารางและจะช่วยเพิ่มความเร็ว

  • ใช้ดิสก์ที่เร็วที่สุดเท่าที่จะทำได้ คุณไม่ได้บอกว่าคุณใช้ดิสก์อะไร แต่คุณสามารถใช้ SSD ได้

  • เพิ่มประสิทธิภาพ tempdb ใส่ tempdb บนดิสก์ที่เร็วที่สุดเท่าที่จะเป็นไปได้ SSD อีกครั้ง เห็นนี้ดังนั้นบทความนี้และบทความ RedGate

  • ตามที่ระบุไว้ในคำตอบอื่น ๆ การใช้คิวรีแบบเลือกมากขึ้นจะให้ข้อมูลน้อยลงและควรเร็วกว่า

ตอนนี้ลองพิจารณาสิ่งที่เราสามารถทำได้หากเราได้รับอนุญาตให้เพิ่มดัชนี

หากเราไม่ได้พูดถึงคำค้นหาเฉพาะกิจเราจะเพิ่มดัชนีโดยเฉพาะสำหรับชุดคำค้นหาที่ จำกัด ที่ถูกรันกับตาราง เนื่องจากเรากำลังพูดคุยเกี่ยวกับคำถามเฉพาะกิจสิ่งที่สามารถทำได้เพื่อปรับปรุงความเร็วเกือบตลอดเวลา

  • เพิ่มดัชนีคอลัมน์เดียวในแต่ละคอลัมน์ สิ่งนี้ควรให้ SQL Server อย่างน้อยต้องทำงานด้วยเพื่อปรับปรุงความเร็วสำหรับแบบสอบถามส่วนใหญ่ แต่จะไม่เหมาะสมที่สุด
  • เพิ่มดัชนีเฉพาะสำหรับข้อความค้นหาที่พบบ่อยที่สุดเพื่อให้ได้รับการปรับให้เหมาะสม
  • เพิ่มดัชนีเฉพาะเพิ่มเติมตามต้องการโดยการตรวจสอบการสืบค้นที่มีประสิทธิภาพต่ำ

แก้ไข

ฉันได้ทำการทดสอบบนตาราง 'ใหญ่' 22 ล้านแถว ตารางของฉันมีเพียงหกคอลัมน์ แต่มีข้อมูล 4GB เครื่องของฉันเป็นเดสก์ท็อปที่มีประสิทธิภาพพร้อม RAM 8Gb และ CPU Quad Core และมี Agility 3 SSD เพียงตัวเดียว

ฉันลบดัชนีทั้งหมดออกจากคีย์หลักในคอลัมน์ Id

แบบสอบถามที่คล้ายกับปัญหาที่ระบุในคำถามจะใช้เวลา 5 วินาทีหากเซิร์ฟเวอร์ SQL ถูกรีสตาร์ทก่อนและ 3 วินาทีในภายหลัง เห็นได้ชัดว่าที่ปรึกษาการปรับแต่งฐานข้อมูลแนะนำให้เพิ่มดัชนีเพื่อปรับปรุงแบบสอบถามนี้โดยมีการปรับปรุงโดยประมาณ> 99% การเพิ่มดัชนีทำให้เวลาในการสืบค้นเป็นศูนย์อย่างมีประสิทธิภาพ

สิ่งที่น่าสนใจก็คือแผนการสืบค้นของฉันเหมือนกับของคุณ (ด้วยการสแกนดัชนีคลัสเตอร์) แต่การสแกนดัชนีคิดเป็น 9% ของต้นทุนการสืบค้นและการจัดเรียงอีก 91% ที่เหลือ ฉันสามารถสมมติว่าตารางของคุณมีข้อมูลจำนวนมหาศาลและ / หรือดิสก์ของคุณช้ามากหรืออยู่บนการเชื่อมต่อเครือข่ายที่ช้ามาก


2

แม้ว่าคุณจะมีดัชนีในคอลัมน์บางคอลัมน์ที่ใช้ในบางข้อความค้นหา แต่การที่ข้อความค้นหา "เฉพาะกิจ" ของคุณทำให้เกิดการสแกนตารางแสดงว่าคุณมีดัชนีไม่เพียงพอที่จะทำให้การสืบค้นนี้เสร็จสมบูรณ์

สำหรับช่วงวันที่โดยเฉพาะการเพิ่มดัชนีที่ดีเป็นเรื่องยาก

เพียงแค่ดูที่แบบสอบถามของคุณฐานข้อมูลจะต้องเรียงลำดับระเบียนทั้งหมดตามคอลัมน์ที่เลือกเพื่อให้สามารถส่งคืน n ระเบียนแรกได้

db ทำการสแกนแบบเต็มตารางโดยไม่ต้องเรียงลำดับตามข้อหรือไม่? ตารางมีคีย์หลักหรือไม่หากไม่มี PK ฐานข้อมูลจะต้องทำงานหนักขึ้นเพื่อดำเนินการจัดเรียง


มีคีย์หลักอยู่บนโต๊ะ การสแกนตารางยังปรากฏในแผนการดำเนินการเมื่อดำเนินการselect top 100 * from ER101_ACCT_ORDER_DTL
Lee Tickett

2

เป็นไปได้อย่างไร? หากไม่มีดัชนีบนคอลัมน์ er101_upd_date_iso จะใช้การสแกนดัชนีคลัสเตอร์ได้อย่างไร

ดัชนีคือ B-Tree ที่แต่ละโหนดลีฟชี้ไปที่ 'กลุ่มของแถว' (เรียกว่า 'เพจ' ในคำศัพท์ภายในของ SQL) นั่นคือเมื่อดัชนีเป็นดัชนีที่ไม่ใช่คลัสเตอร์

ดัชนีคลัสเตอร์เป็นกรณีพิเศษซึ่งโหนดลีฟมี 'กลุ่มแถว' (แทนที่จะชี้ไปที่พวกเขา) นั่นคือเหตุผลว่า ...

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

BTW คุณจะได้รับความช่วยเหลือมากขึ้นหากคุณสามารถโพสต์สคีมาตารางของ ER101_ACCT_ORDER_DTL และดัชนีที่มีอยู่ด้วย ... อาจเป็นไปได้ว่าแบบสอบถามสามารถเขียนใหม่เพื่อใช้บางส่วนได้


+1 สำหรับคำตอบ อย่างไรก็ตามความคิดเห็นหนึ่งดัชนีแบบคลัสเตอร์ไม่ได้เร็วขึ้นเสมอไปเพราะอาจอ่าน (อาจเข้าใจผิด) จากคำตอบของคุณ
Gisli

ฉันคิดว่าฉันเข้าใจความแตกต่างระหว่างดัชนีคลัสเตอร์ / ไม่ใช่คลัสเตอร์ แต่ยังไม่เห็นว่าการสืบค้นคอลัมน์ที่ไม่ใช่ส่วนหนึ่งของดัชนีคลัสเตอร์สามารถปรับปรุงได้อย่างไรโดยมีดัชนีคลัสเตอร์ในคอลัมน์อื่น ๆ
Lee Tickett

ใน SQL Server ดัชนีคลัสเตอร์ประกอบด้วยคอลัมน์ทั้งหมด ดัชนีคลัสเตอร์คือสิ่งที่กำหนดวิธีจัดเก็บข้อมูลบนแผ่นดิสก์ เป็นเรื่องยากสำหรับฉันที่จะอธิบาย แต่ถ้าคุณคิดว่าดัชนีเป็นต้นไม้ดัชนีที่ไม่รวมกลุ่มคือต้นไม้และใบไม้ด้านล่างมีข้อมูลที่คุณกำหนดให้เป็นดัชนี สำหรับดัชนีคลัสเตอร์ใบไม้ด้านล่างจะมีคอลัมน์ทั้งหมดในตาราง นี่คือการออกแบบใน SQL Server
Gisli

ฉันเข้าใจ. แต่ฉันคิดว่ากิ่งก้านนั้นขึ้นอยู่กับคอลัมน์ในดัชนีคลัสเตอร์ ดังนั้นถ้าคอลัมน์ที่ฉันกำลังสอบถามไม่ใช่ int เขาจัดกลุ่มดัชนีก็ต้องสแกนทุกสาขา / ใบไม้?
Lee Tickett

1
ฉันไม่เข้าใจ การคาดเดาที่ดีที่สุดของฉันคือเมื่อคุณมีดัชนีที่ไม่เป็นคลัสเตอร์มันถูกสแกนทำให้เกิด I ​​/ O แบบสุ่มจำนวนมาก เมื่อคุณสร้างดัชนีคลัสเตอร์คุณจะกำจัด I / O แบบสุ่มเหล่านั้นหรือไม่ แต่นี่เป็นการคาดเดาฉันไม่พบเหตุผลอื่นใดสำหรับพฤติกรรมนี้ แต่ฉันไม่ใช่ผู้เชี่ยวชาญ
Gisli

1

สาเหตุหนึ่งที่การทดสอบ 1M ของคุณทำงานได้เร็วขึ้นอาจเป็นเพราะตารางอุณหภูมิอยู่ในหน่วยความจำทั้งหมดและจะไปที่ดิสก์ก็ต่อเมื่อเซิร์ฟเวอร์ของคุณประสบกับแรงกดดันจากหน่วยความจำ คุณสามารถสร้างแบบสอบถามของคุณใหม่เพื่อลบลำดับโดยเพิ่มดัชนีคลัสเตอร์ที่ดีและดัชนีที่ครอบคลุมตามที่กล่าวไว้ก่อนหน้านี้หรือสอบถาม DMV เพื่อตรวจสอบความดัน IO เพื่อดูว่าฮาร์ดแวร์เกี่ยวข้องหรือไม่

-- 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 ว่าจะจัดเก็บตารางใดในหน่วยความจำ ฉันไม่อยู่สองสามวัน แต่เมื่อฉันกลับมาฉันจะลองถามคุณ
Lee Tickett

Avg Task Count และ Avg Pending DiskIO Count สูงสุดที่ 4 ฉันยังสงสัยเกี่ยวกับการพยายามบังคับให้ db เข้าสู่ ram
Lee Tickett

0

ฉันรู้ว่าคุณบอกว่าการเพิ่มดัชนีไม่ใช่ทางเลือก แต่นั่นจะเป็นทางเลือกเดียวในการกำจัดการสแกนตารางที่คุณมี เมื่อคุณทำการสแกน SQL Server จะอ่านแถวทั้งหมด 2 ล้านแถวบนตารางเพื่อตอบสนองการสืบค้นของคุณ

นี้บทความให้ข้อมูลเพิ่มเติม แต่จำไว้: Seek = ดี, Scan = ไม่ดี

ประการที่สองคุณไม่สามารถกำจัด select * และเลือกเฉพาะคอลัมน์ที่คุณต้องการได้หรือไม่? ประการที่สามไม่มีประโยค "ที่ไหน"? แม้ว่าคุณจะมีดัชนีเนื่องจากคุณกำลังอ่านทุกสิ่งที่ดีที่สุดที่คุณจะได้รับคือการสแกนดัชนี (ซึ่งดีกว่าการสแกนตาราง แต่ไม่ใช่การค้นหาซึ่งเป็นสิ่งที่คุณควรตั้งเป้าหมายไว้)


ไม่จริงที่ Seek จะดีกว่า Scan เสมอไป บางครั้งการสแกนมีประสิทธิภาพมากกว่า หากไม่เป็นเช่นนั้น M $ จะไม่รวมคำใบ้แบบสอบถาม FORCESCAN ที่เริ่มต้นใน SQL Server 2008 R2 ดูรายละเอียดเพิ่มเติมได้ที่นี่: msdn.microsoft.com/en-us/library/ms181714(v=sql.105).aspxและแม้แต่ที่นี่สำหรับคนที่ต้องการบังคับให้สแกน (คำตอบที่ 3 โดย Adam Haines มีข้อมูลที่ดี): โซเชียล .msdn.microsoft.com / Forums / en-US / transactsql / thread / …
Solomon Rutzky

1
ก่อนอื่นการค้นหาเป็นสิ่งที่ดีสำหรับการค้นหาแบบตรงประเด็น ประการที่สองการสแกนเป็นสิ่งที่ดีสำหรับการสืบค้นช่วงที่ต้องดึงข้อมูลจำนวนมาก ระบบ OLAP จะทำงานได้ไม่ดีหากไม่มีการสแกน ระบบ OLTP จะทำงานได้ไม่ดีหากไม่มีการแสวงหา ทุกอย่างมีที่มาในรูปแบบที่ยิ่งใหญ่ ...
darlove

0

ฉันรู้ว่ามันค่อนข้างนานแล้วตั้งแต่เริ่มต้น ... มีปัญญามากมายในคำตอบเหล่านี้ การจัดทำดัชนีที่ดีเป็นสิ่งแรกเมื่อพยายามปรับปรุงแบบสอบถาม เกือบจะเป็นคนแรก สิ่งแรกที่สุด (เพื่อให้พูดได้) คือการเปลี่ยนแปลงโค้ดเพื่อให้มีประสิทธิภาพ ดังนั้นหลังจากพูดและทำเสร็จแล้วหากมีคำถามที่ไม่มี WHERE หรือเมื่อเลือกเงื่อนไข WHERE ไม่เพียงพอมีทางเดียวเท่านั้นที่จะรับข้อมูล: TABLE SCAN (INDEX SCAN) หากต้องการคอลัมน์ทั้งหมดจากตารางก็จะใช้ TABLE SCAN - ไม่มีคำถามเกี่ยวกับเรื่องนี้ นี่อาจเป็นการสแกนฮีปหรือการสแกนดัชนีคลัสเตอร์ขึ้นอยู่กับประเภทของการจัดระเบียบข้อมูล วิธีสุดท้ายในการเร่งความเร็ว (ถ้าเป็นไปได้ทั้งหมด) คือการตรวจสอบให้แน่ใจว่ามีการใช้คอร์มากที่สุดในการสแกน: OPTION (MAXDOP 0) ฉันไม่สนใจเรื่องของพื้นที่เก็บข้อมูลแน่นอน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.