Я працюю над оптимізацією деяких запитів.
Для запиту нижче:
SET STATISTICS IO ON;
DECLARE @OrderStartDate DATETIME2 = '27 feb 2016';
DECLARE @OrderEndDate DATETIME2 = '28 feb 2016';
SELECT o.strBxOrderNo
, o.sintOrderStatusID
, o.sintOrderChannelID
, o.sintOrderTypeID
, o.sdtmOrdCreated
, o.sintMarketID
, o.strOrderKey
, o.strOfferCode
, o.strCurrencyCode
, o.decBCShipFullPrice
, o.decBCShipFinal
, o.decBCShipTax
, o.decBCTotalAmount
, o.decWrittenTotalAmount
, o.decBCWrittenTotalAmount
, o.decBCShipOfferDisc
, o.decBCShipOverride
, o.decTotalAmount
, o.decShipTax
, o.decShipFinal
, o.decShipOverride
, o.decShipOfferDisc
, o.decShipFullPrice
, o.lngAccountParticipantID
, CONVERT(DATE, o.sdtmOrdCreated, 120) as OrderCreatedDateConverted
FROM tablebackups.dbo.tblBOrder o
WHERE o.sdtmOrdCreated >= @OrderStartDate
AND o.sdtmOrdCreated < @OrderEndDate
AND EXISTS (
SELECT *
FROM tablebackups.dbo.tblBOrderItem oi
WHERE oi.strBxOrderNo = o.strBxOrderNo
AND oi.decCatItemPrice > 0
)
OPTION (RECOMPILE);
Я створив наступний ФІЛЬТРОВАНИЙ індекс:
-- table dbo.tblBorderItem
CREATE NONCLUSTERED INDEX IX_tblBOrderItem_decCatItemPrice_INCL
ON dbo.tblBorderItem
(
strBxOrderNo ASC
, sintOrderSeqNo ASC
, decCatItemPrice
)
INCLUDE
(
blnChargeShipping
, decBCCatItemPrice
, decBCCostPrice
, decBCFinalPrice
, decBCOfferDiscount
, decBCOverrideDiscount
, decBCTaxAmount
, decCostPrice
, decFinalPrice
, decOfferDiscount
, decOverrideDiscount
, decTaxAmount
, decWasPrice
, dtmOrdItemCreated
, sintOrderItemStatusId
, sintOrderItemType
, sintQuantity
, strItemNo
)
WHERE decCatItemPrice > 0
WITH (DROP_EXISTING = ON, FILLFACTOR = 95);
Цей індекс не використовується тільки для цього запиту, зокрема, є й інші запити, які використовують цей самий індекс, тому колонки ВКЛЮЧЕНІ.
Зокрема, для цього запиту я просто хочу перевірити, чи є у замовлення якийсь предмет де decCatItemPrice > 0
.
SQL Server робить індексне сканування, як ви бачите на малюнках нижче.
- Статистика щойно оновлена.
- Таблиця елементів має 41 208 рядків у тесті.
Зауважте, я не вибираю жодних стовпців із таблиці елементів.
Таблиця предметів налічує 164 309 397 у прямому ефірі. Я хотів би уникнути сканування там.
питання:
Чому SQL Server не здійснює пошук індексу?
Чи є інші фактори / речі, які слід враховувати, щоб покращити цей запит?
(4537 row(s) affected) Table 'tblBorder'. Scan count 1, logical reads
116, physical reads 0, read-ahead reads 0, lob logical reads 0, lob
physical reads 0, lob read-ahead reads 0. Table 'tblBorderItem'. Scan
count 1, logical reads 689, physical reads 0, read-ahead reads 0, lob
logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
це визначення та індекси таблиці tblBorderItem
IF OBJECT_ID('[dbo].[tblBorderItem]') IS NOT NULL
DROP TABLE [dbo].[tblBorderItem]
GO
CREATE TABLE [dbo].[tblBorderItem] (
[strBxOrderNo] VARCHAR(20) NOT NULL,
[sintOrderSeqNo] SMALLINT NOT NULL,
[sintOrderItemStatusId] SMALLINT NOT NULL,
[sintNameStructureID] SMALLINT NOT NULL,
[strItemNo] VARCHAR(20) NOT NULL,
[sintQuantity] SMALLINT NOT NULL,
[strCurrencyCode] VARCHAR(3) NOT NULL,
[decCostPrice] DECIMAL(18,4) NOT NULL,
[decCatItemPrice] DECIMAL(18,2) NOT NULL,
[decOfferDiscount] DECIMAL(18,2) NOT NULL,
[decOverrideDiscount] DECIMAL(18,2) NOT NULL,
[decFinalPrice] DECIMAL(18,2) NOT NULL,
[decTaxAmount] DECIMAL(18,2) NOT NULL,
[strBCCurrencyCode] VARCHAR(3) NOT NULL,
[decBCCostPrice] DECIMAL(18,4) NOT NULL,
[decBCCatItemPrice] DECIMAL(18,4) NOT NULL,
[decBCOfferDiscount] DECIMAL(18,4) NOT NULL,
[decBCOverrideDiscount] DECIMAL(18,4) NOT NULL,
[decBCFinalPrice] DECIMAL(18,4) NOT NULL,
[decBCTaxAmount] DECIMAL(18,4) NOT NULL,
[dtmOrdItemCreated] DATETIME NOT NULL,
[blnChargeShipping] BIT NOT NULL,
[lngTimeOfOrderQtyOnHand] INT NULL,
[sdtmTimeOfOrderDueDate] SMALLDATETIME NULL,
[lngProdSetSeqNo] INT NULL,
[lngProdRelationId] INT NULL,
[lngProdRelationMemberId] INT NULL,
[decWasPrice] DECIMAL(18,2) NULL,
[sintOrderItemType] SMALLINT NULL,
[tsRowVersion] TIMESTAMP NULL,
[sdtmOrderItemStatusUpdated] SMALLDATETIME NULL,
CONSTRAINT [PK_tblBOrderItem]
PRIMARY KEY CLUSTERED
([strBxOrderNo] asc, [sintOrderSeqNo] asc)
WITH FILLFACTOR = 100)
GO
CREATE NONCLUSTERED INDEX
[IX_tblBOrderItem__dtmOrdItemCreated]
ON [dbo].[tblBorderItem] ([dtmOrdItemCreated] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [IX_tblBOrderItem__sintOrderItemStatusId]
ON [dbo].[tblBorderItem] ([sintOrderItemStatusId] asc)
INCLUDE ([sdtmOrderItemStatusUpdated],
[sintOrderSeqNo], [strBxOrderNo], [strItemNo])
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [IX_tblBOrderItem__
sintOrderItemStatusId_decFinalPrice_
sdtmOrderItemStatusUpdated_
include_strBxOrderNo]
ON [dbo].[tblBorderItem]
([sintOrderItemStatusId] asc,
[decFinalPrice] asc,
[sdtmOrderItemStatusUpdated] asc)
INCLUDE ([strBxOrderNo])
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [IX_tblBOrderItem__strBxOrderNo]
ON [dbo].[tblBorderItem]
([strBxOrderNo] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [IX_tblBOrderItem__strItemNo]
ON [dbo].[tblBorderItem] ([strItemNo] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrderItem_decCatItemPrice_INCL]
ON [dbo].[tblBorderItem]
([strBxOrderNo] asc, [sintOrderSeqNo] asc, [decCatItemPrice] asc)
INCLUDE ([blnChargeShipping],
[decBCCatItemPrice], [decBCCostPrice], [decBCFinalPrice],
[decBCOfferDiscount], [decBCOverrideDiscount],
[decBCTaxAmount], [decCostPrice], [decFinalPrice],
[decOfferDiscount], [decOverrideDiscount],
[decTaxAmount], [decWasPrice], [dtmOrdItemCreated],
[sintOrderItemStatusId], [sintOrderItemType],
[sintQuantity], [strItemNo])
WHERE ([decCatItemPrice]>(0))
WITH FILLFACTOR = 95
це визначення та індекси таблиці tblBorder
IF OBJECT_ID('[dbo].[tblBorder]') IS NOT NULL
DROP TABLE [dbo].[tblBorder]
GO
CREATE TABLE [dbo].[tblBorder] (
[strBxOrderNo] VARCHAR(20) NOT NULL,
[uidOrderUniqueID] UNIQUEIDENTIFIER NOT NULL,
[sintOrderStatusID] SMALLINT NOT NULL,
[sintOrderChannelID] SMALLINT NOT NULL,
[sintOrderTypeID] SMALLINT NOT NULL,
[blnIsBasket] BIT NOT NULL,
[sdtmOrdCreated] SMALLDATETIME NOT NULL,
[sintMarketID] SMALLINT NOT NULL,
[strOrderKey] VARCHAR(20) NOT NULL,
[strOfferCode] VARCHAR(20) NOT NULL,
[lngShippedToParticipantID] INT NOT NULL,
[lngOrderedByParticipantID] INT NOT NULL,
[lngShipToAddressID] INT NOT NULL,
[lngAccountAddressID] INT NOT NULL,
[lngAccountParticipantID] INT NOT NULL,
[lngOrderedByAddressID] INT NOT NULL,
[lngOrderTakenBy] INT NOT NULL,
[strCurrencyCode] VARCHAR(3) NOT NULL,
[decShipFullPrice] DECIMAL(18,2) NOT NULL,
[decShipOfferDisc] DECIMAL(18,2) NOT NULL,
[decShipOverride] DECIMAL(18,2) NOT NULL,
[decShipFinal] DECIMAL(18,2) NOT NULL,
[decShipTax] DECIMAL(18,2) NOT NULL,
[strBCCurrencyCode] VARCHAR(3) NOT NULL,
[decBCShipFullPrice] DECIMAL(18,4) NOT NULL,
[decBCShipOfferDisc] DECIMAL(18,4) NOT NULL,
[decBCShipOverride] DECIMAL(18,4) NOT NULL,
[decBCShipFinal] DECIMAL(18,4) NOT NULL,
[decBCShipTax] DECIMAL(18,4) NOT NULL,
[decTotalAmount] DECIMAL(18,2) NOT NULL,
[decBCTotalAmount] DECIMAL(18,4) NOT NULL,
[decWrittenTotalAmount] DECIMAL(18,2) NULL,
[decBCWrittenTotalAmount] DECIMAL(18,4) NULL,
[blnProRataShipping] BIT NOT NULL,
[blnChargeWithFirstShipment] BIT NOT NULL,
[sintShippingServiceLevelID] SMALLINT NOT NULL,
[sintShippingMethodID] SMALLINT NOT NULL,
[sdtmDoNotShipUntil] SMALLDATETIME NULL,
[blnHoldUntilComplete] BIT NOT NULL,
[tsRowVersion] TIMESTAMP NULL,
CONSTRAINT [PK_tblBOrder]
PRIMARY KEY CLUSTERED
([strBxOrderNo] asc) WITH FILLFACTOR = 100)
GO
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__lngAccountAddressID]
ON [dbo].[tblBorder]
([lngAccountAddressID] asc, [sintOrderStatusID] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__lngAccountParticipantID]
ON [dbo].[tblBorder]
([lngAccountParticipantID] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__lngOrderedByAddressID]
ON [dbo].[tblBorder]
([lngOrderedByAddressID] asc, [sintOrderStatusID] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__lngOrderedByParticipantID]
ON [dbo].[tblBorder] ([lngOrderedByParticipantID] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__lngShippedToParticipantID]
ON [dbo].[tblBorder]
([lngShippedToParticipantID] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__lngShipToAddressID]
ON [dbo].[tblBorder]
([lngShipToAddressID] asc, [sintOrderStatusID] asc)
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder__sdtmOrdCreated_sintMarketID__include_strBxOrderNo]
ON [dbo].[tblBorder]
([sdtmOrdCreated] asc, [sintMarketID] asc)
INCLUDE ([strBxOrderNo])
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX
[IX_tblBOrder_sdtmOrdCreated_INCL]
ON [dbo].[tblBorder]
([sdtmOrdCreated] asc)
INCLUDE ([decBCShipFinal], [decBCShipFullPrice],
[decBCShipOfferDisc], [decBCShipOverride],
[decBCShipTax], [decBCTotalAmount], [decBCWrittenTotalAmount],
[decShipFinal], [decShipFullPrice], [decShipOfferDisc],
[decShipOverride], [decShipTax], [decTotalAmount],
[decWrittenTotalAmount], [lngAccountParticipantID],
[lngOrderedByParticipantID], [sintMarketID],
[sintOrderChannelID], [sintOrderStatusID],
[sintOrderTypeID], [strBxOrderNo], [strCurrencyCode],
[strOfferCode], [strOrderKey])
WITH FILLFACTOR = 100
CREATE NONCLUSTERED
INDEX [IX_tblBOrder_sintMarketID_sdtmOrdCreated]
ON [dbo].[tblBorder]
([sintMarketID] asc, [sdtmOrdCreated] asc)
INCLUDE ([sintOrderChannelID], [strBxOrderNo])
WITH FILLFACTOR = 100
CREATE NONCLUSTERED
INDEX [IX_tblBOrder__sintOrderChannelID_sdtmOrdCreated_INCL]
ON [dbo].[tblBorder]
([sintOrderChannelID] asc, [sdtmOrdCreated] asc)
INCLUDE ([decBCShipFinal], [decBCShipFullPrice],
[decBCShipTax], [decShipFinal], [decShipFullPrice],
[decShipTax], [lngAccountParticipantID], [sintMarketID],
[sintOrderTypeID], [strBxOrderNo],
[strCurrencyCode], [strOrderKey])
WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [IX_tblBOrder_strBxOrderNo_sdtmOrdCreated_incl]
ON [dbo].[tblBorder] ([strBxOrderNo] asc,
[sdtmOrdCreated] asc)
INCLUDE ([sintOrderChannelID], [sintOrderTypeID], [sintMarketID],
[strOrderKey], [lngAccountParticipantID], [strCurrencyCode],
[decShipFullPrice], [decShipFinal], [decShipTax],
[decBCShipFullPrice], [decBCShipFinal],
[decBCShipTax])
Висновок
Я застосував свій індекс у системі LIVE та оновив збережену процедуру для використання SMALLDATETIME, щоб відповідати типам даних у базі даних для відповідних стовпців.
Після цього, дивлячись на план запитів, я бачу малюнок нижче:
саме так я хотіла.
Я думаю, що оптимізатор запитів у цьому випадку зробив хорошу роботу, щоб отримати найкращий план запитів для обох середовищ, і я радий, що не додав підказки щодо запитів.
Я дізнався з опублікованими 3 відповідями. дякую Максу Вернону , Полю Уайту та Даніелю Хатмахеру за відповіді.