提高大表上的SQL Server查询性能


85

我有一个相对较大的表(当前有200万条记录),想知道是否有可能提高即席查询的性能。临时一词在这里是关键。添加索引不是一种选择(最常见查询的列上已经有索引)。

运行一个简单的查询以返回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.

该服务器运行sql server 2008 r2 x64的功能非常强大(内存48GB ram,24核处理器)。

更新资料

我发现此代码创建具有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 2012年

4
Table Scan表示(无聚簇索引)-因此第一步将是向您的表中添加良好,快速的聚簇索引。第二步可能是调查非聚簇索引是否er101_upd_date_iso会有所帮助(并且不会导致其他性能缺陷)
marc_s 2012年

1
@marc_s谢谢您-我将pk索引更改为簇索引,并且产生了很大的不同-您可以进一步解释吗?(请
参阅

2
好了,聚集索引只是改变了表的存储布局。聚集索引在其叶级节点中包含实际的表数据-即:为了读取整个表,SQL Server现在正在进行聚集索引扫描(基本上是对具有聚集索引的表进行“表扫描”)。这几乎总是比在堆上进行表扫描(没有聚集索引)要快很多。如果现在在er101_upd_date_iso列上添加了非聚集索引,则可能还可以摆脱执行计划中的“排序”操作,从而进一步加快处理速度
marc_s 2012年

2
@LeeTickett,请显示您的表和索引定义。有许多因素需要考虑,似乎没有人要求它们(这让我感到惊讶,但也许不应该这样)。我可以告诉您200万行不是很大,具有2亿多行的正确索引表的返回速度比这快。聚集索引(很可能要感谢marc_s)很可能是一个糟糕的选择,但很难说清楚具体细节。不要使用分区,而要使用SET STATISTICS IO ON并检查“消息”选项卡中的“逻辑读取”。如果更改减少了“逻辑读取”,您将越来越近。
所罗门·鲁兹基

Answers:


59

简单答案:不。您无法在聚集索引上具有50%填充因子的238列表上帮助临时查询。

详细答案:

正如我在有关该主题的其他答案中所指出的那样,索引设计既是艺术又是科学,并且有太多因素需要考虑,几乎没有硬性规定和快速规定。您需要考虑:DML操作与SELECT的数量,磁盘子系统,表上的其他索引/触发器,表内数据的分布,使用SARGable WHERE条件进行的查询以及其他一些我什至不记得的事情现在。

我可以说,如果不了解表本身,表的索引,触发器等,就无法对有关此主题的问题给予任何帮助。现在您已经发布了表定义(仍在等待索引,但是表定义本身指向问题的99%)我可以提供一些建议。

首先,如果表定义正确(238列,填充系数为50%),那么您几乎可以忽略此处的其余答案/建议;-)。很抱歉,这里的政治性不强,但严重的是,这是不知具体的大事。现在我们看到了表的定义,这使得为什么即使测试查询(更新#1)运行得如此之快,为什么一个简单的查询却要花费这么长时间就变得更加清楚。

这里(以及在许多性能不佳的情况下)的主要问题是不良的数据建模。238列不是被禁止的,就像没有999个索引是被禁止的一样,但这通常也不是很明智。

建议:

  1. 首先,此表确实需要重塑。如果这是一个数据仓库表,那么也许可以,但如果不是这样,则确实需要将这些字段分解为几个可以具有相同PK的表。您将拥有一个主记录表,而子表只是基于共同关联属性的从属信息,这些表的PK与主表的PK相同,因此与主表的PK也相同。主表与所有子表之间将存在一对一的关系。
  2. 使用ANSI_PADDING OFF令人不安,更不用说表格中的不一致,因为随着时间的推移会增加各种列。不知道您现在是否可以解决此问题,但是理想情况下,您ANSI_PADDING ON在所有ALTER TABLE语句中始终会具有,或者至少具有相同的设置。
  3. 考虑创建另外两个文件组:表和索引。最好不要放东西,PRIMARY因为那是SQL SERVER存储其所有数据和有关对象的元数据的地方。在上创建表和聚集索引(即表的数据),在上创建[Tables]所有非聚集索引[Indexes]
  4. 将填充系数从50%增加。这个较低的数字可能是您的索引空间大于数据空间的原因。进行索引重建将重新创建用于数据的最大4k(总8k页面大小中的最大值)的数据页,以便您的表分布在广阔的区域中。
  5. 如果大多数或所有查询的WHERE条件中都包含“ ER101_ORG_CODE” ,请考虑将其移至聚簇索引的前列。假设它比“ 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(或更新的版本),虽然在这种特定情况下无济于事当该时间到来时)并且如果没有更新表,则可以选择使用列存储索引。有关该新功能的更多详细信息,请参见此处:http : //msdn.microsoft.com/zh-cn/library/gg492088.aspx(我认为这些功能可从SQL Server 2014开始进行更新)。

更新2
其他注意事项是:

  • 在聚集索引上启用压缩。该选项在SQL Server 2008中可用,但仅作为企业版功能使用。但是,从SQL Server 2016 SP1开始所有版本均提供数据压缩功能!有关行和页面压缩的详细信息,请参见MSDN页面上的数据压缩。
  • 如果不能使用数据压缩,或者如果它不特定表提供多少好处,然后如果有一个固定长度的类型的一列(INTBIGINTTINYINTSMALLINTCHARNCHARBINARYDATETIMESMALLDATETIMEMONEY,等等)和超过50 %的行是NULL,然后考虑启用SPARSESQL Server 2008中可用的选项。有关详细信息,请参见MSDN页面上的Use Sparse Columns

在7点我个人想象,它应该是更快地从元数据增加238个名比解析出来的查询文本,然后无论如何都要检查元数据,以确保他们都exist.There反对足够强大的论据*没有这种可疑的一个
马丁·史密斯

53

此查询存在一些问题(这适用于每个查询)。

缺乏索引

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查询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 2012年

4
该答案仅解决了提高示例查询的速度,而不是提高“是否有可能提高即席查询的性能”的问题
Phil

CDE现在是CTE(公用表表达式)
sqluser

12

您正在那里进行表扫描,这意味着您没有在上定义索引er101_upd_date_iso,或者如果该列是现有索引的一部分,则无法使用该索引(可能不是主索引器列)。

添加丢失的索引将帮助性能永无止境。

列上已经有索引,这是最常见的查询

这并不意味着它们会在此查询中使用(可能没有使用)。

我建议阅读Gail Shaw的第1部分第2部分,查找在SQL Server中性能不佳的原因。


我的观点是,这不是最常查询的列之一:)
Lee Tickett 2012年

1
@LeeTickett-但是,这是您唯一可以添加索引以改善查询性能的列。
Oded 2012年

2
没有优化的非索引搜索之类的东西。您正在使用索引或全表扫描。如果您不希望进行完整的表扫描,则需要索引。根据您的使用情况配置文件,仅添加索引可能足够便宜。哦,列的数据类型也很重要。如果您er101_upd_date_iso是一个巨大的varchar或一个int,将显着改变性能。
Cylindric

谢谢。我已经对问题添加了评论。我赞赏我不太可能优化查询,但是我想可能有一些方法可以改善即席查询的性能
Lee Tickett 2012年

我是一个学习者,我们如何知道哪个列需要索引?
病毒

7

该问题专门指出临时查询的性能需要提高,并且不能添加索引。因此,从表面上看,可以采取什么措施来提高任何表的性能?

由于我们正在考虑临时查询,因此WHERE子句和ORDER BY子句可以包含任何列组合。这意味着几乎不管表上放置了什么索引,都会有一些需要进行表扫描的查询,如上图所示,在执行不佳查询的查询计划中。

考虑到这一点,我们假设除了主键上的聚簇索引外,表上根本没有索引。现在,让我们考虑一下我们必须使用哪些选项来最大化性能。

  • 整理表碎片

    只要我们具有聚集索引,就可以使用DBCC INDEXDEFRAG(不推荐使用)或最好使用ALTER INDEX对表进行碎片整理。这样可以减少扫描表所需的磁盘读取次数,并提高速度。

  • 使用最快的磁盘。您没有说要使用什么磁盘,而是可以使用SSD。

  • 优化tempdb。将tempdb放在可能最快的磁盘上,再放在SSD上。请参阅此SO文章和此RedGate文章

  • 如其他答案所述,使用更具选择性的查询将返回较少的数据,因此应更快。

现在让我们考虑如果允许添加索引该怎么办。

如果我们不是在讨论即席查询,那么我们将专门针对针对该表运行的有限查询集添加索引。由于我们正在讨论临时查询,因此大多数时候可以采取哪些措施来提高速度?

  • 向每列添加一个列索引。这应该使SQL Server至少可以使用某些东西来提高大多数查询的速度,但这并不是最佳选择。
  • 为最常见的查询添加特定的索引,以便对其进行优化。
  • 通过监视性能不佳的查询,根据需要添加其他特定索引。

编辑

我已经对2200万行的“大”表进行了一些测试。我的表只有六列,但确实包含4GB的数据。我的机器是一个受人尊敬的台式机,具有8Gb RAM和一个四核CPU,并具有一个Agility 3 SSD。

我删除了除ID列上的主键以外的所有索引。

如果首先重新启动SQL Server,则与问题中给出的问题类似的查询需要5秒钟,然后需要3秒钟。数据库调优顾问显然建议添加索引以改进此查询,估计可提高99%以上。添加索引会导致查询时间实际上为零。

有趣的是,我的查询计划与您的查询计划相同(使用聚集索引扫描),但是索引扫描占查询成本的9%,而排序则占其余91%。我只能假设您的表包含大量数据和/或您的磁盘非常慢或位于非常慢的网络连接上。


2

即使您在某些查询中使用的某些列上都有索引,您的“临时”查询会导致表扫描的事实表明您没有足够的索引来使此查询有效地完成。

特别是对于日期范围,很难添加良好的索引。

仅查看查询,数据库就必须按所选列对所有记录进行排序,以便能够返回前n条记录。

db是否也执行不带order by子句的全表扫描?该表是否具有主键-如果没有PK,数据库将不得不更加努力地执行排序?


桌上有一个主键。当简单执行时,表扫描也会出现在执行计划中select top 100 * from ER101_ACCT_ORDER_DTL
Lee Tickett 2012年

2

这怎么可能?在er101_upd_date_iso列上没有索引的情况下,如何使用聚集索引扫描?

索引是一个B树,其中每个叶节点都指向“行束”(在SQL内部术语中称为“页面”),也就是说,该索引是非聚集索引。

聚集索引是一种特殊情况,其中叶节点具有“行束”(而不是指向它们)。这就是为什么...

1)表上只能有一个聚集索引。

这也意味着整个表都存储为聚集索引,这就是为什么您开始看到索引扫描而不是表扫描的原因。

2)利用聚集索引的操作通常比非聚集索引快

http://msdn.microsoft.com/zh-cn/library/ms177443.aspx上了解更多信息

对于您遇到的问题,您确实应该考虑将此列添加到索引,因为您说添加新索引(或将列添加到现有索引)会增加INSERT / UPDATE成本。但是有可能删除一些未充分利用的索引(或现有索引中的列)以替换为“ er101_upd_date_iso”。

如果无法更改索引,我建议在列上添加统计信息,当列与索引列有某些关联时,它可以加快处理速度

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

顺便说一句,如果您可以发布ER101_ACCT_ORDER_DTL的表模式,您将获得更多帮助。以及现有的索引...,可能可以重写查询以使用其中的一些索引。


+1为答案。不过,只有一条评论,因为从索引中可以读取(可能会误解),所以聚集索引并不总是更快。
Gisli 2012年

我想我了解聚簇/非聚簇索引之间的区别,但是仍然看不到如何通过在其他列上具有聚簇索引来改善不属于聚簇索引的列的查询?
Lee Tickett 2012年

在SQL Server中,聚集索引包含所有列。聚集索引是决定数据如何存储在光盘上的因素。我很难解释,但是如果您将索引视为一棵树,则非聚簇索引就是一棵树,并且底部的叶子包含您定义为索引旅馆的信息。对于聚集索引,最下面的叶子包含表中的所有列。这是设计使然的SQL Server。
Gisli 2012年

我明白了。但是我认为分支基于聚集索引中的列。因此,如果我要查询的列不是整数,那么肯定需要扫描每个分支/叶子的聚簇索引吗?
Lee Tickett 2012年

1
我不明白 我最好的猜测是,当您拥有未聚簇的索引时,会对其进行扫描,从而导致大量的随机I / O。创建聚簇索引时,您摆脱了那些随机I / O吗?但这是一个猜测,我找不到其他任何原因导致这种行为,但我不是专家。
Gisli 2012年

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 2012年

平均任务计数和平均未决DiskIO计数达到4的峰值。我仍然对尝试将数据库强制进入ram感到好奇。
Lee Tickett 2012年

0

我知道您说过添加索引不是一种选择,但是这将是消除表扫描的唯一选择。进行扫描时,SQL Server读取表上的所有200万行以完成查询。

这个文章提供了更多的信息,但要记住:寻求=好,扫描=坏。

其次,您是否不能消除select *并仅选择所需的列?第三,没有“ where”子句?即使您有索引,由于您正在阅读所有内容,因此您将获得最好的结果是索引扫描(这比表扫描要好,但它不是寻道,这是您应该追求的目标)


并不是说Seek总是比Scan更好。有时,扫描实际上更有效。如果不是这种情况,则M $不会包括从SQL Server 2008 R2开始的FORCESCAN查询提示。有关更多详细信息,请参见此处:msdn.microsoft.com/zh-cn/library/ms181714(v=sql.105).aspx,甚至对于希望强制执行扫描的人员也在此处(Adam Haines的第3个回答都提供了很好的信息):社交.msdn.microsoft.com /论坛/ EN-US / TRANSACTSQL /线程/ ...
所罗门Rutzky

1
好吧,首先,搜索对于类似点的查询很有用。其次,扫描对于必须检索大量数据的范围查询很有用。如果没有扫描,OLAP系统将无法正常运行。OLTP系统如果没有搜索就不会表现良好。一切都在宏伟的事物中占有一席之地……
darlove

0

我知道从开始就已经有一段时间了...所有这些答案中都有很多智慧。尝试改善查询时,首先要做好索引编制。好吧,几乎是第一个。首先(可以这么说)是对代码进行更改,以使其高效。因此,说完一切之后,如果一个查询没有WHERE,或者当WHERE条件没有足够的选择性时,只有一种获取数据的方式:TABLE SCAN(INDEX SCAN)。如果需要一张表中的所有列,那么将使用TABLE SCAN-毫无疑问。根据数据组织的类型,这可能是堆扫描或群集索引扫描。加快速度的唯一最后方法(如果可能的话)是确保使用尽可能多的内核来进行扫描:OPTION(MAXDOP 0)。我当然会忽略存储的主题,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.