2009-06-23 3 views
1

У меня есть две таблицыSQL Присоединение занимает много времени

(1) MonthlyTarget {SalesManCode, TargetMonthYear, TargetValue}; Эта таблица имеет 1966177 строк.

(2) MonthlySales {SalesManCode, SaleDate, AchievedValue}; 

В этой таблице 400310 строк.

Я должен сделать запрос, который дает результат, как в следующей таблице:

{SalesManCode, JanTar, JanAch, FebTar, FebAch,....., DecTar, DecAch} 

Проблема заключается в том, соединяющий эти две таблицы занимает много времени.

Какой должен быть запрос?

Как оптимизировать запрос?

Я не хочу рассматривать индексацию.

+1

Не могли бы вы опубликовать ваше текущее заявление и, возможно, мы можем видеть, что вы делаете? –

+1

Почему нет индексации? – n8wrl

+3

Почему вы не хотите рассматривать индексацию? Если ваши причины не индексирования очень прочные, я бы пересмотрел, поскольку индексация, вероятно, будет лучшим способом повышения производительности здесь. – mwigdahl

ответ

3

Похоже, что в таблице MonthlyTarget вам не хватает некоторых столбцов , а именно: «TargetD ate ".

В дополнение к тому, что все уже говорили об индексировании, иногда подход с разделением и победой может действительно помочь.Вместо того, чтобы присоединиться таблицей с 1966177 строк в таблицу строк 400310, создать для маленьких временных таблиц и соединить их вместе, вместо этого:

CREATE TABLE #MonthlySalesAgg 
(
    SalesManCode int, 
    JanTar money, 
    FebTar money, 
    MarTar money, 
    AprTar money, 
    MayTar money, 
    JunTar money, 
    JulTar money, 
    AugTar money, 
    SepTar money, 
    OctTar money, 
    NovTar money, 
    DecTar money 

    PRIMARY KEY CLUSTERED (SalesManCode) 
) 

INSERT INTO #MonthlySalesAgg 
SELECT * 
FROM 
(SELECT SalesManCode, TargetValue, SaleMonth = Month(TargetDate) FROM MonthlyTarget) as temp 
PIVOT 
(
    Max(TargetValue) 
    FOR [SaleMonth] IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]) 
) as p 

CREATE TABLE #MonthlyTargetAgg 
(
    SalesManCode int, 
    JanAch money, 
    FebAch money, 
    MarAch money, 
    AprAch money, 
    MayAch money, 
    JunAch money, 
    JulAch money, 
    AugAch money, 
    SepAch money, 
    OctAch money, 
    NovAch money, 
    DecAch money 

    PRIMARY KEY CLUSTERED (SalesManCode) 
) 

INSERT INTO #MonthlyTargetAgg 
SELECT * FROM 
(SELECT SalesManCode, AchievedValue, SaleMonth = Month(SaleDate) FROM MonthlySales) as temp 
PIVOT 
(
    Sum(AchievedValue) 
    FOR [SaleMonth] IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]) 
) as p 

Запросов выше создать две промежуточных таблицы, которые должны содержать одинаковое количество записей в качестве коммивояжера таблицы , Вместе с ними проста:

SELECT * 
FROM #MonthlyTargetAgg target 
INNER JOIN #MonthlySalesAgg sales ON target.SalesManCode = sales.SalesManCode 

Если вы окажетесь необходимости вытаскивать данные за месяц все время, перенесите код в вид вместо.

PIVOT требует SQL Server 2005 или более поздней версии, и часто это очень полезный оператор. Надеемся, что SQL Server 2008 позволит пользователям поворачиваться более чем на один столбец за раз, что приведет к еще более простому запросу, чем показано выше.

Использование SQL Server 2000:

PIVOT является синтаксисом. Например,

SELECT * FROM 
(SELECT SalesManCode, AchievedValue, SaleMonth = Month(SaleDate) FROM MonthlySales) as temp 
PIVOT 
(
    Sum(AchievedValue) 
    FOR [SaleMonth] IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]) 
) as p 

Становится

SELECT 
    SalesManCode, 
    [1] = Sum(case SaleMonth when 1 then AchievedValue else 0 end), 
    [2] = Sum(case SaleMonth when 2 then AchievedValue else 0 end), 
    [3] = Sum(case SaleMonth when 3 then AchievedValue else 0 end), 
    [4] = Sum(case SaleMonth when 4 then AchievedValue else 0 end), 
    [5] = Sum(case SaleMonth when 5 then AchievedValue else 0 end), 
    [6] = Sum(case SaleMonth when 6 then AchievedValue else 0 end), 
    [7] = Sum(case SaleMonth when 7 then AchievedValue else 0 end), 
    [8] = Sum(case SaleMonth when 8 then AchievedValue else 0 end), 
    [9] = Sum(case SaleMonth when 9 then AchievedValue else 0 end), 
    [10] = Sum(case SaleMonth when 10 then AchievedValue else 0 end), 
    [11] = Sum(case SaleMonth when 11 then AchievedValue else 0 end), 
    [12] = Sum(case SaleMonth when 12 then AchievedValue else 0 end) 
FROM 
    (SELECT SalesManCode, AchievedValue, SaleMonth = Month(SaleDate) FROM MonthlySales) as temp 
GROUP BY SalesManCode 
+0

Как я могу достичь этого в SQL Server 2000? – 2009-06-24 13:22:22

+0

Я обновил свой код с переводом PIVOT на то, что работает в SQL Server 2000. – Juliet

+0

+1 - хорошее объяснение реализации операции PIVOT и актуальности в реальном мире. Красиво сделано. – karlgrz

3

Проверьте правильность индексирования таблиц. Почти невозможно сказать, не глядя на саму базу, но 99% случаев медленных объединений связаны с неправильными или отсутствующими индексами таблицы.

0

У вас есть фильтры? Не могли бы вы сохранить некоторые частичные результаты в temp-таблице, а затем присоединиться к остальным данным после того, как вы уменьшили размер ваших данных?

4

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

0

Если индексирование не является вариантом, единственный способ ускорить его - поставить его на более быстрый сервер. Что-то подсказывает, что индексация будет проще.

1

Я не хочу рассматривать индексацию.

Вы должны учитывать индексацию. Неважно, как вы пишете запрос, у db-движка нет выбора, кроме как сканировать каждую таблицу, которая ищет соединения, и это, вероятно, повторит это снова и снова. У вас нет выбора.

Если вы не хотите связываться с индексацией, потому что у вас нет контроля над базой данных, рассмотрите возможность экспорта данных в локальный экземпляр SQL Express.

Heck, даже экспортируя данные в плоские файлы, сортируя файлы SalesManCode и записывая простую программу для чтения и сопоставления, будет быстрее.

1

Коротких стрельбы кучи людей продаж, рассмотреть следующие варианты:

  • создать пакетный процесс, чтобы запустить эту каждую ночь и заселить некоторые таблицы отчетов с выходом вашего запроса
  • создать индексированный/(хотя вам нужно будет создать индекс в индексированном представлении, так что, возможно, это нарушает правило без индексов)
Смежные вопросы