Выбранные столбцы влияют на план выполнения?

У меня есть запрос, что-то вроде этого. У него есть план выполнения с использованием индекса, который я ожидаю, до тех пор, пока количество данных (то есть количество символов), возвращаемых SELECT, не превысит границу. В этот момент план больше не использует индекс, и запрос становится в 100+ раз медленнее.

Если я использую NVARCHAR(203), это быстро. NVARCHAR(204) медленный. Кроме того, когда он не использует индекс, он полностью сжигает ЦП. По крайней мере, мне кажется, что это проблема размера данных, но я ищу любую информацию.

Я изменил oldValueString и newValueString на NVARCHAR(255), и все стало немного лучше, но я все еще не могу запросить все столбцы без потери индекса в плане.

SELECT
   [Lx_AuditColumn].[auditColumnPK],
   CONVERT(NVARCHAR(204), [Lx_AuditColumn].[newValueString])
FROM
   [dbo].[Lx_AuditColumn] [Lx_AuditColumn],
   [dbo].[Lx_AuditTable] [Lx_AuditTable]
WHERE
   [Lx_AuditColumn].[auditTableFK] = [Lx_AuditTable].[auditTablePK]
AND
   [Lx_AuditTable].[createdDate] >=  @P1
AND
   [Lx_AuditTable].[createdDate] <=  @P2
ORDER BY
   [Lx_AuditColumn].[auditColumnPK] DESC

Это базовая структура таблиц (я исключил некоторые индексы и ограничения FK).

CREATE TABLE [dbo].[Lx_AuditTable]
(
   [auditTablePK] [int] NOT NULL IDENTITY(1, 1) ,
   [firmFK] [int] NOT NULL ,
   [auditMasterFK] [int] NOT NULL ,
   [codeSQLTableFK] [int] NOT NULL ,
   [objectFK] [int] NOT NULL ,
   [projectEntityID] [int] NULL ,
   [createdByFK] [int] NOT NULL ,
   [createdDate] [datetime] NOT NULL ,
   CONSTRAINT [Lx_PK_AuditTable_auditTablePK] PRIMARY KEY CLUSTERED
   (
      [auditTablePK]
   ) WITH FILLFACTOR = 90
)
GO

CREATE INDEX [Lx_IX_AuditTable_createdDatefirmFK]
   ON [dbo].[Lx_AuditTable]([createdDate], [firmFK])
   INCLUDE ([auditTablePK], [auditMasterFK])
   WITH (FILLFACTOR = 90, ONLINE = OFF)
GO

CREATE TABLE [dbo].[Lx_AuditColumn]
(
   [auditColumnPK] [int] NOT NULL IDENTITY(1, 1) ,
   [firmFK] [int] NOT NULL ,
   [auditTableFK] [int] NOT NULL ,
   [accessorName] [nvarchar] (100) NOT NULL ,
   [dataType] [nvarchar] (20) NOT NULL ,
   [oldValueNumber] [int] NULL ,
   [oldValueString] [nvarchar] (4000) NULL ,
   [newValueNumber] [int] NULL ,
   [newValueString] [nvarchar] (4000) NULL ,
   [newValueText] [ntext] NULL ,
   CONSTRAINT [Lx_PK_AuditColumn_auditColumnPK] PRIMARY KEY CLUSTERED
   (
      [auditColumnPK]
   ) WITH FILLFACTOR = 90 ,
   CONSTRAINT [Lx_FK_AuditColumn_auditTableFK] FOREIGN KEY
   (
      [auditTableFK]
   ) REFERENCES [dbo].[Lx_AuditTable] (
      [auditTablePK]
   )
)
GO

CREATE INDEX [Lx_IX_AuditColumn_auditTableFK]
   ON [dbo].[Lx_AuditColumn]([auditTableFK])
   WITH (FILLFACTOR = 90, ONLINE = OFF)
GO

Хороший:

введите здесь описание изображения

Плохо:

введите здесь описание изображения


person rar    schedule 24.08.2012    source источник
comment
Можете ли вы опубликовать (1) планы выполнения для обоих случаев и (2) структуру таблицы (столбцы, типы данных, длины) и (3) любую информацию об индексах в этой таблице?   -  person marc_s    schedule 24.08.2012
comment
Но да, оптимизатор запросов SQL Server определит достаточно хороший план запроса, а размер данных и количество перемещаемых данных определенно являются главными факторами, влияющими на определение того, является ли поиск по индексу (быстрым) стоит, и когда это становится слишком дорогим, вместо этого будет использоваться сканирование таблицы или сканирование кластерного индекса.   -  person marc_s    schedule 24.08.2012
comment
Пожалуйста, не добавляйте теги HTML (например, <br>) во фрагменты кода. Прочтите справку по редактированию, прежде чем задавать вопрос.   -  person Himanshu Jansari    schedule 24.08.2012
comment
Мой ответ здесь может пролить свет на это   -  person Martin Smith    schedule 26.08.2012


Ответы (3)


С этой настройкой - без подробного знания структуры таблицы (пока) - вы обязательно должны:

  • иметь хороший кластеризованный индекс для таблицы dbo.Lx_AuditColumn (что-то вроде INT IDENTITY почти идеально)
  • некластеризованный индекс на Lx_AuditColumn.auditTableFK для ускорения JOIN и проверки ссылочной целостности
  • некластеризованный индекс на Lx_AuditColumn.AuditColumnPK (если это уже не кластеризованный PK, конечно!)
  • некластеризованный индекс на Lx_AuditTable.CreatedDate

Кроме того: вы должны использовать правильный синтаксис стандарта ANSI/ISO Standard INNER JOIN (вместо простого списка таблиц, разделенных запятыми, для выбора — см. Плохие привычки, которые следует исключить: использование JOIN в старом стиле для справочной информации по этой теме) — используйте этот запрос:

SELECT
   [Lx_AuditColumn].[auditColumnPK],
   CONVERT(NVARCHAR(204), [Lx_AuditColumn].[newValueString])
FROM
   [dbo].[Lx_AuditColumn] [Lx_AuditColumn]
INNER JOIN
   [dbo].[Lx_AuditTable] [Lx_AuditTable] ON [Lx_AuditColumn].[auditTableFK] = [Lx_AuditTable].[auditTablePK]
WHERE
   [Lx_AuditTable].[createdDate] >=  @P1
   AND
   [Lx_AuditTable].[createdDate] <=  @P2
ORDER BY
   [Lx_AuditColumn].[auditColumnPK] DESC
person marc_s    schedule 24.08.2012

Хотя я не могу дать элегантного решения этой проблемы (помимо обычных вещей, таких как индексы, статистика, индексированные представления), я могу решить проблему хаком:

Преобразуйте запрос, чтобы использовать синтаксис JOIN, и примените подсказку:

INNER HASH JOIN ...

Это приведет к хеш-соединению, а также зафиксирует порядок соединения.

Это нехорошо, потому что SQL Server больше не может адаптироваться к меняющимся схемам и данным.

person usr    schedule 24.08.2012
comment
Прежде чем сократить столбцы NVARCHAR, я попробовал это, но это не очень помогло. Однако INNER MERGE JOINT сделал это. После того, как я сократил столбцы, мне вообще не пришлось менять запрос. Спасибо, - Рэнди - person rar; 26.08.2012

Я изменил oldValueString и newValueString на NVARCHAR(255), и все стало немного лучше. Однако после того, как я принудительно воссоздал таблицу с укороченными столбцами, все вернулось к «нормальному состоянию». Я добавил поддельный столбец nvarchar(10), использовал режим разработки, чтобы преобразовать его в int (т.е. заставить дизайнера создать новую таблицу и скопировать данные), а затем удалил лишний столбец. Возможно, отказ от сервера или что-то еще решило бы эту проблему, но я смог сделать это так, без отказа от сервера.

person rar    schedule 26.08.2012