提高大型表上的 SQL Server 查询性能
Posted
技术标签:
【中文标题】提高大型表上的 SQL Server 查询性能【英文标题】:Improve SQL Server query performance on large tables 【发布时间】:2012-04-19 00:20:10 【问题描述】:我有一个相对较大的表(目前有 200 万条记录),想知道是否可以提高临时查询的性能。 ad-hoc 是这里的关键。添加索引不是一种选择(在最常查询的列上已经有索引)。
运行一个简单的查询以返回最近更新的 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 内存,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
感谢 cmets - 请让他们继续来......他们引导我尝试将主键索引从非集群更改为集群,结果相当有趣(和意外?)。
非集群:
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。
【问题讨论】:
当您将鼠标光标悬停在计划项目上时,会有一些提示。它们显示了估计的 I/O 和 CPU 成本。一开始我会考虑 I/O 成本。Table Scan
表示一个堆(无聚集索引) - 所以第一步是添加一个良好、快速的聚集索引到你的桌子。第二步可能是调查er101_upd_date_iso
上的非聚集索引是否会有所帮助(并且不会导致其他性能缺陷)
@marc_s 谢谢你-我将 pk 索引更改为集群,它产生了实质性的差异-你能进一步解释一下吗? (查看更新 2)
嗯,聚集索引只是改变了表的存储布局。聚集索引在其叶级节点中包含实际的表数据——也就是说:为了读取整个表,SQL Server 现在正在执行聚集索引扫描(基本上是对具有聚集索引的表的“表扫描”)。这几乎总是比在堆上进行表扫描(没有聚集索引)快很多。如果您现在在 er101_upd_date_iso
列上添加了一个非聚集索引,您可能还可以摆脱执行计划中的“排序”操作,从而加快速度
@LeeTickett,请显示您的表和索引定义。有很多因素需要考虑,似乎没有人要求他们(这让我感到惊讶,但也许不应该)。我可以告诉你,200 万行并不大,并且具有 2 亿多行的正确索引表的返回速度比这更快。很可能聚集索引(现在你有了一个,多亏了 marc_s)是一个糟糕的选择,但如果不看细节就很难说。不要使用分区,但要使用 SET STATISTICS IO ON 并检查消息选项卡中的逻辑读取。如果更改减少了逻辑读取,那么您离我们越来越近了。
【参考方案1】:
简单的答案:不。对于 238 列的表,聚集索引的填充因子为 50%,您无法帮助进行临时查询。
详细回答:
正如我在有关该主题的其他答案中所述,索引设计既是艺术又是科学,需要考虑的因素太多,因此几乎没有(如果有的话)硬性规定。您需要考虑:DML 操作与 SELECT 的数量、磁盘子系统、表上的其他索引/触发器、表内的数据分布、使用 SARGable WHERE 条件的查询以及其他一些我什至记不清的事情现在。
我可以说,如果不了解表本身、它的索引、触发器等,就无法对有关此主题的问题提供任何帮助。现在您已经发布了表定义(仍在等待索引,但表定义单独指出问题的 99%)我可以提供一些建议。
首先,如果表格定义准确(238 列,50% 填充因子),那么您几乎可以忽略此处的其余答案/建议;-)。很抱歉在这里没有政治色彩,但说真的,这是一场不知道具体情况的疯狂追逐。现在我们看到了表定义,就更清楚为什么一个简单的查询会花费这么长时间,即使测试查询(更新 #1)运行得如此之快。
这里的主要问题(以及在许多性能不佳的情况下)是糟糕的数据建模。 238列是不被禁止的,就像999个索引是不被禁止的一样,但通常也不是很明智。
建议:
-
首先,这张桌子确实需要改造。如果这是一个数据仓库表,那么可能,但如果不是,那么这些字段确实需要分成几个表,它们都可以具有相同的 PK。您将拥有一个主记录表,子表只是基于通常关联属性的依赖信息,并且这些表的 PK 与主表的 PK 相同,因此也与主表的 FK 相同。主表和所有子表之间将存在一对一的关系。
ANSI_PADDING OFF
的使用令人不安,更不用说由于随着时间的推移添加了各种列而导致的表内不一致。不确定您现在是否可以解决此问题,但理想情况下您将始终拥有 ANSI_PADDING ON
,或者至少在所有 ALTER TABLE
语句中具有相同的设置。
考虑创建 2 个额外的文件组:表和索引。最好不要把你的东西放在PRIMARY
中,因为这是 SQL SERVER 存储它的所有数据和关于你的对象的元数据的地方。您在[Tables]
上创建表和聚集索引(因为这是表的数据),在[Indexes]
上创建所有非聚集索引
将填充因子从 50% 增加。这个低数字可能是您的索引空间大于数据空间的原因。执行索引重建将重新创建用于数据的最大 4k 数据页面(总页面大小为 8k),以便您的表格分布在广阔的区域。
如果大多数或所有查询在WHERE
条件中都有“ER101_ORG_CODE”,则考虑将其移至聚集索引的前导列。假设它比“ER101_ORD_NBR”更常用。如果更频繁地使用“ER101_ORD_NBR”,请保留它。看起来,假设字段名称表示“OrganizationCode”和“OrderNumber”,“OrgCode”是一个更好的分组,其中可能包含多个“OrderNumber”。
次要问题,但如果“ER101_ORG_CODE”始终为 2 个字符,则使用 CHAR(2)
而不是 VARCHAR(2)
,因为它将在行标题中保存一个字节,该字节跟踪可变宽度大小并加起来超过数百万行。
正如这里的其他人所提到的,使用SELECT *
会影响性能。不仅因为它要求 SQL Server 返回所有列,因此无论您的其他索引如何,都更有可能进行聚集索引扫描,而且 SQL Server 还需要时间去表定义并将*
转换为所有列名。在SELECT
列表中指定所有 238 个列名应该稍微快一些,但这对扫描问题没有帮助。但是,您是否真的需要同时使用所有 238 列?
祝你好运!
更新 为了完整地回答“如何提高临时查询的大型表的性能”这个问题,应该注意的是,虽然它对这种特定情况没有帮助,但如果有人使用 SQL Server 2012(或更新版本)那个时候到了)并且如果表没有被更新,那么使用列存储索引是一个选项。有关该新功能的更多详细信息,请查看此处: http://msdn.microsoft.com/en-us/library/gg492088.aspx(我相信这些是从 SQL Server 2014 开始可更新的)。
更新 2 其他注意事项是:
在聚集索引上启用压缩。此选项在 SQL Server 2008 中可用,但仅作为企业版功能。但是,从 SQL Server 2016 SP1 开始,数据压缩功能可用in all editions!有关行和页面压缩的详细信息,请参阅 Data Compression 的 MSDN 页面。 如果您不能使用数据压缩,或者如果它不会为特定表提供太多好处,那么如果您有一个固定长度类型的列(INT
、BIGINT
、TINYINT
、@ 987654340@、CHAR
、NCHAR
、BINARY
、DATETIME
、SMALLDATETIME
、MONEY
等)并且超过 50% 的行是NULL
,然后考虑启用SPARSE
选项它在 SQL Server 2008 中可用。有关详细信息,请参阅 Use Sparse Columns 的 MSDN 页面。
【讨论】:
就第 7 点个人而言,我认为从元数据中添加 238 个列名应该比从查询文本中解析它们然后必须检查元数据以确保它们都存在更快。有反对*
的论据足够有力,没有那个可疑的人【参考方案2】:
我知道从开始到现在已经有很长一段时间了......所有这些答案都有很多智慧。尝试改进查询时,良好的索引是第一件事。嗯,几乎是第一个。最先(可以这么说)是对代码进行更改以使其高效。所以,说到底,如果一个查询没有 WHERE,或者当 WHERE 条件的选择性不够时,只有一种方法可以获取数据:TABLE SCAN (INDEX SCAN)。如果需要表中的所有列,则将使用 TABLE SCAN - 毫无疑问。这可能是堆扫描或聚集索引扫描,具体取决于数据组织的类型。加快速度的唯一最后一种方法(如果可能的话)是确保使用尽可能多的内核来进行扫描:OPTION (MAXDOP 0)。当然,我忽略了存储的主题,但是应该确保一个有无限的 RAM,这是不言而喻的 :)
【讨论】:
【参考方案3】:此查询存在一些问题(这适用于每个查询)。
缺少索引
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
优点:
轻松处理任何数据子集。 易于管理——它是临时的,它是table。 不会像view
那样影响整体系统性能。
临时表可以被索引。
您不必关心它——它是暂时的 :)。
缺点:
它是数据的快照——但这对于大多数即席查询来说可能已经足够了。2。公用表表达式——CTE
就我个人而言,我经常将 CTE 用于即席查询——它对逐个构建(和测试)查询很有帮助。
参见下面的示例(以WITH
开头的查询)。
优点:
易于构建,从大视图开始,然后选择和过滤您真正需要的内容。 易于测试。缺点:
有些人不喜欢 CDE - CDE 查询似乎很长且难以理解。3。创建视图
与上面类似,但创建视图而不是临时表(如果您经常使用相同的查询并且您拥有支持索引视图的 MS SQL 版本。
您可以在您感兴趣的数据子集上创建视图或indexed views 并在视图上运行查询——它应该只包含比整个表小得多的有趣数据子集。
优点:
很容易做到。 源数据是最新的。缺点:
仅适用于已定义的数据子集。 对于更新率较高的大型表可能效率低下。 不太容易管理。 可能会影响整体系统性能。 我不确定每个版本的 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
脏读
最后一件可以加快临时查询的事情是允许 dirty reads 使用table hint WITH (NOLOCK)
。
您可以set transaction isolation level 阅读未提交的内容,而不是提示:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
或设置适当的 SQL Management Studio 设置。
我认为对于临时查询脏读就足够了。
【讨论】:
+1 forSELECT *
-- 它强制 SQL Server 使用聚集索引。至少,它应该。我没有看到非聚集覆盖索引的任何真正原因......覆盖整个表:)
这个答案只涉及提高示例查询的速度,而不是“是否可以提高临时查询的性能”的问题
CDE 现在是 CTE(公用表表达式)【参考方案4】:
该问题明确指出ad-hoc 查询的性能需要改进,并且不能添加索引。那么从表面上看,可以做些什么来提高任何桌子的性能?
由于我们正在考虑即席查询,WHERE 子句和 ORDER BY 子句可以包含列的任意组合。这意味着几乎不管表上放置了哪些索引,都会有一些查询需要表扫描,如上面在性能不佳查询的查询计划中所见。
考虑到这一点,我们假设除了主键上的聚集索引之外,表上根本没有索引。现在让我们考虑一下我们有哪些选项可以最大限度地提高性能。
对表格进行碎片整理
只要我们有一个聚集索引,我们就可以使用DBCC INDEXDEFRAG(已弃用)或最好使用ALTER INDEX 对表进行碎片整理。 这将最大限度地减少扫描表所需的磁盘读取次数并提高速度。
尽可能使用最快的磁盘。你没有说你正在使用什么磁盘,但你是否可以使用 SSD。
优化 tempdb。将 tempdb 放在尽可能快的磁盘上,同样是 SSD。请参阅此SO Article 和此RedGate article。
正如其他答案中所述,使用更具选择性的查询将返回更少的数据,因此应该更快。
现在让我们考虑一下,如果允许我们添加索引,我们可以做什么。
如果我们不讨论临时查询,那么我们将专门为针对表运行的有限查询集添加索引。 由于我们正在讨论 ad-hoc 查询,大多数情况下可以做些什么来提高速度?
为每列添加一个单列索引。这应该让 SQL Server 至少可以使用一些东西来提高大多数查询的速度,但不会是最佳的。 为最常见的查询添加特定索引,以便优化它们。 根据需要添加额外的特定索引,以监控性能不佳的查询。编辑
我在一个包含 2200 万行的“大”表上运行了一些测试。我的表只有六列,但包含 4GB 的数据。我的机器是一台性能不错的台式机,配备 8Gb RAM 和四核 CPU,并且有一个 Agility 3 SSD。
我删除了 Id 列上除主键之外的所有索引。
如果首先重新启动 SQL Server,则与问题中给出的问题类似的查询需要 5 秒,随后需要 3 秒。数据库调优顾问显然建议添加一个索引来改进这个查询,估计改进 > 99%。添加索引会导致查询时间实际上为零。
另外有趣的是,我的查询计划与你的相同(使用聚集索引扫描),但索引扫描占查询成本的 9%,排序占剩余的 91%。我只能假设您的表包含大量数据和/或您的磁盘非常慢或位于非常慢的网络连接上。
【讨论】:
【参考方案5】:我知道您说过添加索引不是一种选择,但这是消除您拥有的表扫描的唯一选择。当您进行扫描时,SQL Server 会读取表上的所有 200 万行来完成您的查询。
this 文章提供了更多信息,但请记住:Seek = 好,Scan = 坏。
第二,你不能去掉select *,只选择你需要的列吗? 第三,没有“where”子句?即使您有索引,由于您正在阅读所有内容,因此您将获得的最佳结果是索引扫描(这比表扫描更好,但它不是查找,这是您应该瞄准的目标)
【讨论】:
Seek 总是比 Scan 更好的说法是不正确的。有时扫描实际上更有效。如果不是这种情况,则 M$ 将不会包含从 SQL Server 2008 R2 开始的 FORCESCAN 查询提示。有关更多详细信息,请参见此处:msdn.microsoft.com/en-us/library/ms181714(v=sql.105).aspx 甚至在这里寻找强制扫描的人(亚当海恩斯的第三个答案有很好的信息):social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… 嗯,首先,搜索适用于点状查询。其次,扫描适用于必须检索大量数据的范围查询。如果没有扫描,OLAP 系统将无法正常运行。如果没有搜索,OLTP 系统将无法正常运行。一切在事物的宏伟计划中都有自己的位置......【参考方案6】:这怎么可能?如果 er101_upd_date_iso 列上没有索引,如何使用聚集索引扫描?
索引是一个 B 树,其中每个叶节点都指向一个“行”(在 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
顺便说一句,如果您可以发布 ER101_ACCT_ORDER_DTL 的表架构,您将获得更多帮助。 以及现有的索引......,也许可以重写查询以使用其中的一些。
【讨论】:
+1 为答案。不过,有一条评论,聚集索引并不总是更快,因为人们可能会从您的答案中读取(可能会误解它)。 我想我了解聚集索引/非聚集索引之间的区别,但仍然看不到如何通过在其他索引上使用聚集索引来改进查询不属于聚集索引的列列? 在 SQL Server 中,聚集索引包含所有列。聚集索引决定了数据在磁盘上的存储方式。我有点难以解释,但是如果您将索引视为一棵树,那么非聚集索引就是一棵树,底部的叶子包含您定义为索引的信息。对于聚集索引,底部叶子包含表中的所有列。这是 SQL Server 设计的。 我明白了。但我认为分支是基于聚集索引中的列。因此,如果我要查询的列不是聚集索引,那么肯定需要扫描每个分支/叶子吗? 我不明白。我最好的猜测是,当你有一个非聚集索引时,它被扫描会导致大量随机 I/O。当您创建聚集索引时,您摆脱了那些随机 I/O?但这是一个猜测,我找不到任何其他原因导致这种行为,但我不是专家。【参考方案7】:您的 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 哪些表存储在内存中?我已经离开了几天,但是当我回来时,我会尝试您的查询-谢谢 Avg Task Count 和 Avg Pending DiskIO Count 在 4 处达到峰值。我仍然对尝试将 db 强制进入 ram 感到好奇。【参考方案8】:即使您在某些查询中使用的某些列上有索引,但您的“临时”查询会导致表扫描这一事实表明您没有足够的索引来让该查询有效地完成。
特别是对于日期范围,很难添加好的索引。
仅查看您的查询,数据库必须按所选列对所有记录进行排序才能返回前 n 条记录。
数据库是否也在没有 order by 子句的情况下进行全表扫描?表是否有主键 - 没有 PK,数据库将不得不更加努力地执行排序?
【讨论】:
桌子上有一个主键。简单执行select top 100 * from ER101_ACCT_ORDER_DTL
时,执行计划中也会出现表扫描【参考方案9】:
您正在那里进行表扫描,这意味着您没有在er101_upd_date_iso
上定义的索引,或者如果该列是现有索引的一部分,无法使用索引(可能不是主索引器列)。
添加缺少的索引将有助于提高性能。
查询频率最高的列上已有索引
这并不意味着在此查询中使用了它们(它们可能不会)。
我建议阅读 Gail Shaw、part 1 和 part 2 的《寻找 SQL Server 性能不佳的原因》。
【讨论】:
我的意思是,这不是最常查询的列之一 :) @LeeTickett - 然而,这是唯一可以添加索引以提高 this 查询性能的列。 没有优化的非索引搜索之类的东西。您要么使用索引,要么使用全表扫描。如果您不想要全表扫描,则需要索引。根据您的使用情况,只需添加索引可能就足够便宜了。哦,列的数据类型也很重要。如果您的er101_upd_date_iso
是一个巨大的 varchar 或 int,则会显着改变性能。
谢谢。我已经对这个问题添加了评论。我很感激我不太可能优化查询-但我想可能有一些方法可以提高临时查询的性能
我是一个学习者,我们怎么知道哪一列需要索引?以上是关于提高大型表上的 SQL Server 查询性能的主要内容,如果未能解决你的问题,请参考以下文章