2009-05-12 1 views
3

У меня есть запрос sql с внутренними объединениями четырех таблиц, которые занимают более 30 секунд с текущими индексами и структурой запросов. Я хотел бы сделать это как можно быстрее; по крайней мере, быстрее, чем 5 секунд.Какие индексы оптимизируют этот запрос с четырьмя объединениями?

Сначала я подумал о денормализации, но прочитал here, что в принципе можно оптимизировать с помощью правильных индексов и т. Д. В этом случае я не могу понять. Текущий план запроса содержит сканирование индекса в самой маленькой таблице и предупреждение о недопустимом соединении в одном из внутренних соединений.

  • Как я могу оптимизировать скорость следующего?
  • Какие индексы?
  • Какая структура запросов?
  • Другие соображения?

Мы следующие таблицы (с числом строк и соответствующих полей указывается):

 
TableName   Rows Fields 
------------------- ----- ---------------------------------------------- 
ProjectType   150 ProjectTypeID, ProjectTypeName 
Employee   200 EmployeeID, RefDepartmentID 
Project    0.2M ProjectID, RefProjectTypeID 
ProjectTransaction 3.5M Hours, RefEmployeeID, RefProjectID, Date, Type 

Запрос должен подвести часы для данного отдела, диапазон дат и т.д. В настоящее время я пытаюсь:

SELECT E.RefDepartmentID, SUM(PTran.Hours) 
FROM Employee E 
JOIN ProjectTransaction PTran 
    ON E.EmployeeID = PTran.RefEmployeeID 
JOIN Project P 
    ON PTran.RefProjectID = P.ProjectID 
JOIN ProjectType PType 
    ON P.RefProjectTypeID = PType.ProjectTypeID 
WHERE E.RefDepartmentID = @departmentID 
    AND @from <= PTran.Date AND PTran.Date <= @to 
    AND PTran.Type = 0 
    AND PType.ProjectTypeName NOT IN (N'1', N'2', N'3') 
GROUP BY E.RefDepartmentID 

Спасибо за все быстрые ответы. (У меня уже были индексы по «внешним ключам» и критериям в предложении WHERE.) Я переупорядочил запрос, чтобы сначала иметь две маленькие таблицы, затем средний размер, а большой - последний. И вояла занимает около одной секунды:

SELECT E.RefDepartmentID, SUM(PTran.Hours) 
FROM Employee E 
JOIN ProjectType PType 
    ON E.RefCustomerID = PType.RefCustomerID 
JOIN Project P 
    ON PType.ProjectTypeID = P.RefProjectTypeID 
JOIN ProjectTransaction PTran 
    ON E.EmployeeID = PTran.RefEmployeeID 
    AND P.ProjectID = PTran.RefProjectID 
WHERE E.RefDepartmentID = @departmentID 
    AND @from <= PTran.Date AND PTran.Date <= @to 
    AND PTran.Type = 0 
    AND PType.ProjectTypeName NOT IN (N'1', N'2', N'3') 
GROUP BY E.RefDepartmentID 
+0

Какой сервер баз данных вы используете? В лучшем случае добавьте вопрос тега с именем сервера базы данных. –

ответ

8

Это не всегда работает, но попробуйте:

  1. таблиц REORDER в соединениях от самых маленьких от одного до самого большого.
  2. Использование подзапросов вместо ProjectTransaction таблицы:

    РЕГИСТРИРУЙТЕСЬ (SELECT RefEmployeeID, RefProjectID ОТ ProjectTransaction ГДЕ @from < = PTran.Date И PTran.Date < = @to И PTran.Type = 0) транс

+0

Да, действительно. Это быстрее. Теперь требуется 1 секунда. Благодарю. –

+0

Я забыл сказать, что я сделал: я использовал ваш первый совет: переупорядочивал таблицы с наименьшим первым и самым большим последним. –

+0

+1 крики! От 30 секунд до 1 секунды. – codeulike

1

Удостоверьтесь, что у вас есть индексы на столбцах внешнего ключа.

+0

Спасибо. Да. Столбцы с Ref * (например, RefEmployeeID, RefDepartmentID) относятся к столбцам идентификатора в других таблицах. У меня есть индексы по этим столбцам. Однако они не настроены явно как внешние ключи в базе данных sql. Может ли скорость зависеть от того, что они не являются «истинными» внешними ключами? –

+0

It * возможно * поможет. Это требует тестирования. Если у вас есть внешний ключ в столбце и первичный ключ, другой оптимизатор запросов будет уверен, что в родительской таблице есть одна строка. Это может помочь выполнить запрос более эффективно. Это может повредить производительность INSERT. Хорошо, что они также обеспечивают целостность данных. Чтобы убедиться, что это увеличение или потеря производительности, вы должны попробовать оба и сравнить. –

1

Предполагая, что P.ProjectID и PType.ProjectTypeID являются PRIMARY KEY «s, создать этот индекс:

CREATE INDEX ix_ptran_emloyee_type_date ON ProjectTransaction(RefEmployeeID, Type, Date) 

, и избавиться от GROUP BY:

SELECT @departmentID, SUM(PTran.Hours) 
FROM Employee E 
JOIN ProjectTransaction PTran 
ON  PTran.RefEmployeeID = E.EmployeeID 
JOIN Project P 
ON  P.ProjectID = PTran.RefProjectID 
JOIN ProjectType PType 
ON  PType.ProjectTypeID = P.RefProjectTypeID 
WHERE E.RefDepartmentID = @departmentID 
     AND PTran.Date BETWEEN @from AND @to 
     AND PTran.Type = 0 
     AND PType.ProjectTypeName NOT IN (N'1', N'2', N'3') 
+0

Как вы можете избавиться от GroupBy() и все еще иметь Sum() в Select? – codeulike

+0

Я думаю, что Quassnoi забыл E.RefDepartmentID = @departmentID в предложении WHERE. При включенном включении нет необходимости использовать GROUP BY, потому что кроме SUM нет полей результатов в списке SELECT. Quassnoi выбирает только параметр @departmentID и SUM. –

+0

Конечно, я забыл E.RefDepartmentID = @departmentID – Quassnoi

0

Что говорит ваш план запроса? Если у вас есть два сканирования индексов в одной таблице, за которыми следует хеш-соединение (или подобное) между их результатами, создайте составной индекс с полями из обоих индексов - тогда БД может выполнить один индексный поиск в составном индексе.

Удостоверьтесь, что у вас есть актуальная статистика. База данных может оптимизироваться лучше, если она предоставляется.

1

Указатели на все внешние ключи, очевидно.

Также ProjectTransaction - ваш единственный действительно большой стол, и вы делаете много фильтрации на нем в предложении Where. Я хотел бы добавить индексы для всех столбцов, которые вы фильтрация на:

ProjectTransaction.Date
ProjectTransaction.Type

редактирование: Как у вас есть таблица там с 3,5 миллиона строк, другая оптимизация «техник» вы могли бы хочу рассмотреть возможность обновления оборудования на вашем SQL Server. Некоторая дополнительная память или несколько дополнительных процессоров иногда могут быть более экономически эффективными, чем оптимизированное время разработки (в зависимости от затрат на разработку и сколько оптимизации вы делаете, очевидно) ... например. см. Hardware is Cheap, Programmers are Expensive.

0

Все советы до сих пор звучат, но если вы хотите видеть мнение эксперта (то есть SQL Server), вы можете сделать хуже, чем использовать Database Engine Tuning Advisor. Даже если у вас нет обширных реальных данных, советник может сделать некоторые разумные предложения, основанные на небольшом наборе тестовых данных.

Смежные вопросы