大きなテーブルでのSQLServerクエリのパフォーマンスを向上させる


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;

しかし、3つのテストサーバーでは、クエリはほぼ瞬時に実行されました。誰かがこれを説明できますか?

ここに画像の説明を入力してください

アップデート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.8GBで、インデックスサイズは3.9GBです。


1
プランアイテムの上にマウスカーソルを置くと、ヒントはほとんどありません。これらは、推定I / OおよびCPUコストを示しています。最初はI / Oコストを気にします。
Grzegorz Gierlik 2012

4
Table Scanヒープ(クラスター化インデックスなし)を示します。したがって、最初のステップは、適切で高速なクラスター化インデックスをテーブルに追加することです。2番目のステップは、上の非クラスター化インデックスer101_upd_date_isoが役立つかどうかを調査することかもしれません(そして、他のパフォーマンス上の欠点を引き起こさない)
marc_s 2012

1
@marc_sありがとうございます-pkインデックスをクラスター化に変更しましたが、大幅な違いがありました-これについてさらに説明していただけますか?(アップデート2を参照)
Lee Tickett 2012

2
クラスター化インデックスは、テーブルのストレージレイアウトを変更するだけです。クラスター化インデックスには、リーフレベルノードの実際のテーブルデータが含まれます。つまり、テーブル全体を読み取るために、SQL Serverはクラスター化インデックススキャン(基本的にはクラスター化インデックスを持つテーブルに対する「テーブルスキャン」)を実行しています。これは、ほとんどの場合、ヒープでテーブルスキャンを実行するよりもかなり高速になります(クラスター化インデックスなし)。er101_upd_date_iso列に非クラスター化インデックスを追加した場合は、実行プランの「並べ替え」操作を削除して、処理をさらに高速化することもできます
marc_s 2012

2
@LeeTickett、テーブルとインデックスの定義を表示してください。考慮すべき多くの要因があり、誰もそれらを求めていないようです(これは私を驚かせますが、おそらくそうではないはずです)。200万行は大きくなく、2億行以上の適切にインデックス付けされたテーブルは、これよりも速く返されます。おそらく、クラスター化されたインデックス(marc_sのおかげで1つになりました)は適切な選択ではありませんが、詳細を見ずに言うのは難しいです。パーティショニングは使用しないでください。ただし、SET STATISTICS IO ONを使用して、[メッセージ]タブの[論理読み取り]を確認してください。変更によって論理読み取りが減少する場合は、近づいています。
Solomon Rutzky 2012

回答:


59

簡単な答え:いいえ。クラスター化インデックスのフィルファクターが50%の238列のテーブルに対するアドホッククエリは役に立ちません。

詳細な回答:

このトピックに関する他の回答で述べたように、インデックスのデザインは芸術と科学の両方であり、ハードで高速なルールがあったとしてもごくわずかであると考える要素がたくさんあります。考慮する必要があります:DML操作とSELECTの量、ディスクサブシステム、テーブル上の他のインデックス/トリガー、テーブル内のデータの分散、SARGable WHERE条件を使用したクエリ、および私が正しく覚えていない他のいくつかのこと今。

テーブル自体、そのインデックス、トリガーなどを理解しないと、このトピックに関する質問に役立つことはできないと言えます。テーブル定義を投稿したので(まだインデックスを待っていますが、テーブル定義だけが指している問題の99%)私はいくつかの提案を提供することができます。

まず、テーブルの定義が正確である場合(238列、50%のフィルファクター)、ここでの残りの回答/アドバイスはほとんど無視できます;-)。ここでは政治的ではないことを残念に思いますが、真剣に、それは詳細を知らずに野生のガチョウの追跡です。そして、テーブル定義が表示されたので、テストクエリ(更新#1)が非常に高速に実行された場合でも、単純なクエリに時間がかかる理由がかなり明確になりました。

ここでの(そして多くのパフォーマンスの悪い状況での)主な問題は、悪いデータモデリングです。999のインデックスを持つことが禁止されていないのと同じように、238の列も禁止されていませんが、一般的にはあまり賢明ではありません。

推奨事項:

  1. まず、このテーブルは本当に改造する必要があります。これがデータウェアハウステーブルである場合は多分ですが、そうでない場合は、これらのフィールドをいくつかのテーブルに分割する必要があります。これらのテーブルはすべて同じPKを持つことができます。マスターレコードテーブルがあり、子テーブルは一般的に関連付けられた属性に基づく依存情報であり、これらのテーブルのPKはマスターテーブルのPKと同じであるため、マスターテーブルへのFKも同じです。マスターテーブルとすべての子テーブルの間には1対1の関係があります。
  2. ANSI_PADDING OFF時間の経過とともにさまざまな列が追加されるため、テーブル内で一貫性がないことは言うまでもなく、の使用は厄介です。今すぐ修正できるかどうかはわかりませんが、理想的には、常にANSI_PADDING ON、または少なくともすべてのALTER TABLEステートメントで同じ設定を使用します。
  3. テーブルとインデックスの2つの追加ファイルグループを作成することを検討してください。PRIMARYSQL 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がすべての列を返す必要があるため、他のインデックスに関係なくクラスター化インデックススキャンを実行する可能性が高いだけでなく、SQLServerがテーブル定義に移動*してすべての列名に変換するのにも時間がかかります。。スキャンの問題には役立ちませんが、リスト内の238列の名前すべてを指定する方が少し速いはずSELECTです。しかし、とにかく、238列すべてを同時に本当に必要とすることはありますか?

幸運を!

更新
「アドホッククエリの大きなテーブルのパフォーマンスを向上させる方法」という質問を完全にするために、この特定のケースでは役に立ちませんが、誰かがSQL Server 2012(またはそれ以降)を使用している場合は注意が必要です。その時が来たとき)そしてテーブルが更新されていない場合は、列ストアインデックスを使用することはオプションです。この新機能の詳細については、http//msdn.microsoft.com/en-us/library/gg492088.aspxを参照してください(これらはSQL Server 2014以降で更新可能になっていると思います)。

UPDATE2
追加の考慮事項は次のとおりです。

  • クラスター化インデックスの圧縮を有効にします。このオプションはSQLServer 2008で利用可能になりましたが、EnterpriseEditionのみの機能です。ただし、SQL Server 2016 SP1の時点で、データ圧縮はすべてのエディションで利用可能になりました。行とページの圧縮の詳細については、データ圧縮のMSDNページを参照してください。
  • あなたはデータ圧縮を使用できない場合、またはそれはあなたが固定長型の列を持っている場合は、その後、特定のテーブルのために多くの利益を提供(ない場合はINTBIGINTTINYINTSMALLINTCHARNCHARBINARYDATETIMESMALLDATETIMEMONEY、など)と優に超える50行の%がである場合は、SQL Server 2008で使用可能になっNULLSPARSEオプションを有効にすることを検討してください。詳細については、MSDNページの「スパース列の使用」を参照してください。

ポイント7で個人的には、クエリテキストから238列の名前を解析するよりも、メタデータから238列の名前を追加する方が速いはずだと思います。その後、メタデータをチェックして、すべてが存在することを確認する必要があります。*疑わしいものがなければ、十分に強力な議論があります。
マーティンスミス

53

このクエリにはいくつかの問題があります(これはすべてのクエリに当てはまります)。

インデックスの欠如

er101_upd_date_iso列のインデックスの欠如は、Odedとして最も重要なことですがすでに述べたようにです。

一致するインデックスがないと(不足するとテーブルスキャンが発生する可能性があります)、大きなテーブルで高速クエリを実行する機会はありません。

インデックスを追加できない場合(1つのアドホッククエリに対してインデックスを作成しても意味がないなど、さまざまな理由で)、いくつかの回避策を提案します(アドホッククエリに使用できます)。

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を頻繁に使用します。これは、クエリを1つずつ作成(およびテスト)するのに大いに役立ちます。

以下の例を参照してください(で始まるクエリWITH)。

長所:

  • 大きな視点から始めて、本当に必要なものを選択してフィルタリングすることで、簡単に構築できます。
  • テストが簡単。

短所:

  • CDEを嫌う人もいます-CDEクエリは長くて理解しにくいようです。

3.ビューを作成します

上記と同様ですが、一時テーブルの代わりにビューを作成します(同じクエリを頻繁に使用し、インデックス付きビューをサポートするMSSQLバージョンを使用している場合。

ビューまたはインデックス付きビューを作成できます関心のあるデータのサブセットに対してをに対してクエリを実行できます。これには、テーブル全体よりもはるかに小さい興味深いデータのサブセットのみが含まれている必要があります。

長所:

  • 簡単にできます。
  • ソースデータは最新です。

短所:

  • 定義されたデータのサブセットに対してのみ可能です。
  • 更新率の高い大きなテーブルでは非効率になる可能性があります。
  • 管理はそれほど簡単ではありません。
  • システム全体のパフォーマンスに影響を与える可能性があります。
  • インデックス付きビューがMSSQLのすべてのバージョンで使用できるかどうかはわかりません。

すべての列を選択する

大きなテーブルでスタークエリ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 ManagementStudio設定を設定します。

アドホッククエリの場合、ダーティリードで十分と思います。


2
+ 1for SELECT *-SQLServerにクラスター化インデックスの使用を強制します。少なくとも、そうすべきです。クラスター化されていないカバーインデックスの本当の理由はわかりません...テーブル全体をカバーしています:)
ta.speot.is 2012

4
この回答は、「アドホッククエリのパフォーマンスを向上させることは可能か」という質問ではなく、サンプルクエリの速度の向上のみを対象としています
Phil

CDEは現在CTE(共通テーブル式)です
sqluser 2015

12

あなたは取得しているテーブルスキャンあなたがいることを意味し、そこにインデックスが持っていない上に定義しましたer101_upd_date_iso(おそらくそれは主インデクサー列ではありません)、またはその列は、既存のインデックスの一部である場合、インデックスは使用できません。

不足しているインデックスを追加すると、パフォーマンスに終わりはありません。

最も一般的にクエリされる列にはすでにインデックスがあります

これは、これらがこのクエリで使用されていることを意味するものではありません(おそらく使用されていません)。

GailShawによるSQLServerのパフォーマンス低下の原因の発見、パート1およびパート2を読むことをお勧めします。


私のポイントは、これは最も一般的に照会される列の1つではないということです:)
Lee Tickett 2012

1
@ LeeTickett-それでも、これは、このクエリのパフォーマンスを向上させるためにインデックスを追加できる唯一の列です。
2012

2
最適化されたインデックスなしの検索などはありません。インデックスまたは全表スキャンのいずれかを使用しています。全表スキャンが必要ない場合は、インデックスが必要です。使用プロファイルによっては、インデックスを追加するだけで十分安価な場合があります。ああ、そして列のデータ型も重要です。あなたer101_upd_date_isoが巨大なvarcharまたはintである場合、パフォーマンスが大幅に変化します。
円筒形2012

ありがとう。質問にコメントを追加しました。クエリを最適化できる可能性は低いと
思い

私は学習者ですが、どの列にインデックスを付ける必要があるかをどうやって知ることができますか?
ウイルス

7

この質問では、アドホッククエリのパフォーマンスを改善する必要があり、インデックスを追加できないことが具体的に示されています。それを額面通りに考えると、どのテーブルでもパフォーマンスを向上させるために何ができるでしょうか。

アドホッククエリを検討しているため、WHERE句とORDERBY句には列の任意の組み合わせを含めることができます。これは、テーブルに配置されているインデックスにほとんど関係なく、パフォーマンスの低いクエリのクエリプランで前述したように、テーブルスキャンを必要とするクエリがいくつかあることを意味します。

これを考慮して、主キーのクラスター化インデックスを除いて、テーブルにインデックスがまったくないと仮定します。次に、パフォーマンスを最大化するために必要なオプションについて考えてみましょう。

  • テーブルを最適化する

    限り、我々はクラスタ化インデックスを持っているように、我々は、使用してテーブルを最適化することができるDBCC INDEXDEFRAG(非推奨)、または好ましくは、ALTER INDEXを。これにより、テーブルのスキャンに必要なディスク読み取りの数が最小限に抑えられ、速度が向上します。

  • 可能な限り最速のディスクを使用してください。使用しているディスクはわかりませんが、SSDを使用できるかどうかはわかりません。

  • tempdbを最適化します。tempdbを可能な限り最速のディスク(SSD)に配置します。このSOの記事とこのRedGateの記事を参照してください

  • 他の回答で述べられているように、より選択的なクエリを使用すると、返されるデータが少なくなるため、より高速になります。

次に、インデックスの追加が許可されている場合に何ができるかを考えてみましょう。

アドホッククエリについて話していなかった場合は、テーブルに対して実行される限られたクエリセット専用のインデックスを追加します。アドホッククエリについて説明しているので、ほとんどの場合、速度を向上させるために何ができるでしょうか。

  • 各列に単一の列インデックスを追加します。これにより、SQL Serverは、大部分のクエリの速度を向上させるために少なくとも何かを使用できるようになりますが、最適ではありません。
  • 最も一般的なクエリに特定のインデックスを追加して、最適化されるようにします。
  • パフォーマンスの低いクエリを監視することにより、必要に応じて特定のインデックスを追加します。

編集

私は2200万行の「大きな」テーブルでいくつかのテストを実行しました。私のテーブルには6つの列しかありませんが、4GBのデータが含まれています。私のマシンは、8Gb RAMとクアッドコアCPUを備えた立派なデスクトップであり、単一のAgility 3SSDを備えています。

Id列の主キー以外のすべてのインデックスを削除しました。

質問で与えられた問題と同様のクエリは、SQLサーバーが最初に再起動された場合は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列にインデックスがない場合、クラスター化インデックススキャンをどのように使用できますか?

インデックスは、各リーフノードが「行の束」(SQL内部用語では「ページ」と呼ばれる)を指しているBツリーです。つまり、インデックスが非クラスター化インデックスの場合です。

クラスター化インデックスは特殊なケースであり、リーフノードには(それらを指すのではなく)「行の束」があります。それが理由です...

1)テーブルに存在できるクラスター化インデックスは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。ただし、1つのコメントとして、クラスター化インデックスは、回答から読み取る可能性があるため(誤解される可能性があるため)、常に高速であるとは限りません。
gisli 2012

クラスター化インデックスと非クラスター化インデックスの違いは理解できたと思いますが、クラスター化インデックスを他の列に配置することで、クラスター化インデックスの一部ではない列のクエリを改善する方法がわかりませんか?
Lee Tickett 2012

SQL Serverでは、クラスター化インデックスにはすべての列が含まれます。クラスター化インデックスは、データをディスクに保存する方法を決定するものです。説明するのは少し難しいですが、インデックスをツリーと考えると、非クラスター化インデックスはツリーであり、下部の葉には、インデックスにインとして定義した情報が含まれています。クラスター化インデックスの場合、下部の葉にはテーブル内のすべての列が含まれます。これはSQLServerの仕様によるものです。
gisli 2012

わかりました。しかし、ブランチはクラスター化インデックスの列に基づいていると思いました。それで、私が照会している列がクラスター化インデックスではない場合、すべてのブランチ/リーフをスキャンする必要がありますか?
Lee Tickett 2012

1
わかりません。私の推測では、クラスター化されていないインデックスがある場合、それがスキャンされ、ランダムなI / Oが大量に発生したと考えられます。クラスター化インデックスを作成したときに、これらのランダムI / Oを削除しましたか?しかし、これは推測です。この動作の他の理由は見つかりませんが、私は専門家ではありません。
gisli 2012

1

1Mテストがより速く実行された理由の1つは、一時テーブルが完全にメモリ内にあり、サーバーでメモリ不足が発生した場合にのみディスクに移動するためと考えられます。クエリを作り直してorderbyを削除するか、前述のように適切なクラスター化インデックスとカバーインデックスを追加するか、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に指示したりする方法はありますか?私は数日間
不在

平均タスク数と平均保留中のDiskIO数は4でピークに達しました。私はまだdbをRAMに強制しようとすることに興味があります。
Lee Tickett 2012

0

インデックスを追加することはオプションではないとおっしゃっていましたが、それがテーブルスキャンを排除する唯一のオプションになるでしょう。スキャンを実行すると、SQL Serverはテーブルの200万行すべてを読み取り、クエリを実行します。

この記事はより多くの情報を提供しますが、覚えておいてください:シーク=良い、スキャン=悪い。

次に、select *を削除して、必要な列のみを選択することはできませんか?第三に、「where」句はありませんか?インデックスがある場合でも、すべてを読んでいるので、インデックススキャンが最適です(テーブルスキャンよりも優れていますが、シークではありません。これは、目指すべきものです)。


シークが常にスキャンよりも優れているとは限りません。スキャンが実際により効率的である場合があります。そうでない場合、M $には、SQL Server 2008R2以降のFORCESCANクエリヒントが含まれていませんでした。詳細については、msdn.microsoft.com / en-us / library / ms181714(v = sql.105).aspxを参照してください。スキャンを強制しようとしている人については、ここでも参照してください(Adam Hainesによる3番目の回答には良い情報があります):ソーシャル.msdn.microsoft.com / Forums / en-US / transactsql / thread /…
Solomon Rutzky 2012

1
まず第一に、シークはポイントのようなクエリに適しています。次に、スキャンは、大量のデータを取得する必要がある範囲クエリに適しています。OLAPシステムは、スキャンなしではうまく機能しません。OLTPシステムは、シークなしではうまく機能しません。すべてが...物事の壮大な計画で、その場所を持っている
darlove

0

最初からかなり時間が経っていることを私は知っています...これらすべての答えには多くの知恵があります。クエリを改善しようとするとき、最初に適切なインデックスを作成します。まあ、ほとんど最初。最も最初の(いわば)は、コードを効率的に変更することです。したがって、結局のところ、WHEREのないクエリがある場合、またはWHERE条件が十分に選択的でない場合、データを取得する方法はTABLE SCAN(INDEX SCAN)の1つだけです。テーブルのすべての列が必要な場合は、TABLESCANが使用されます-それについては疑問の余地はありません。これは、データ編成のタイプに応じて、ヒープスキャンまたはクラスター化インデックススキャンの場合があります。処理を高速化する最後の方法は(可能な場合)、スキャンを実行するためにできるだけ多くのコアが使用されていることを確認することです:OPTION(MAXDOP0)。もちろん、私はストレージの主題を無視しています、

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.