Я использую EntityFramework 4 для доступа к базе данных SQL Server 2008.
Один из SQL-запросов, генерируемых EF, имеет поведение, которое я не могу объяснить.
Запрос выглядит так:
SELECT tableA.field1, tableA.field2, ...
FROM tableA join tableB on tableA.field1 = tableB.field1
WHERE
tableA.field2 > '20110825'
and tableA.field3 in ('a', 'b', 'c,')
and tableB.field4 = 'xxx'
Где tableA.field2 - datetime not null
, а остальные поля - varchars.
Таблица A содержит около 1,5 миллионов записей, таблица B содержит около 2 миллионов записей, и запрос возвращает 1877 строк.
Проблема в том, что он возвращает их через 86 секунд, и это время резко меняется, когда я изменяю литерал «20110825» на более старые значения.
Например, если я поставлю '20110725', запрос вернет 3483 строки за 35 миллисекунд.
Я обнаружил в плане выполнения, что разница между ними заключается в индексах, которые SQL Server выбирает для использования в зависимости от даты, используемой для сравнения.
Когда требуется время, план выполнения показывает:
- 50%: поиск по индексу в tableA.field2 (это кластеризованный индекс только для этого поля)
- 50%: поиск индекса по tableB.field1 (неуникальный, некластеризованный индекс только для этого поля)
- 0%: присоединиться
Когда это почти мгновенно, план выполнения показывает:
- 98%: поиск индекса по tableA.field1 (неуникальный, некластеризованный индекс только для этого поля)
- 2%: поиск индекса по tableB.field1 (неуникальный, некластеризованный индекс только для этого поля)
- 0%: присоединиться
Так что мне кажется, что решение оптимизатора использовать кластерный индекс для tableA.field2 не оптимально.
Есть ли недостаток в дизайне базы данных? В запросе SQL?
Могу ли я каким-либо образом заставить базу данных использовать правильный план выполнения?