Агрегированная функция / производительность запроса по группам - PullRequest
1 голос
/ 26 января 2011

Этот запрос работает (спасибо тем, кто помог), чтобы получить 30-дневную скользящую среднюю по объему.

SELECT x.symbol, x.dseqkey, AVG(y.VOLUME) moving_average
FROM STOCK_HIST x, STOCK_HIST y
WHERE x.dseqkey>=29 AND x.dseqkey BETWEEN y.dseqkey AND y.dseqkey+29
AND Y.Symbol=X.Symbol 
GROUP BY x.symbol, x.dseqkey
ORDER BY x.dseqkey DESC

Однако производительность очень плохая. Я запускаю вышеупомянутое представление (STOCK_HIST), которое объединяет две таблицы (A и B). Таблица A содержит ежедневный объем и дневную дату для более чем 9 000 акций, начиная с 40 лет (более 300 строк в год на каждую из 9 000 акций). Таблица B является таблицей «Ключ даты», которая связывает дату в таблице A с DSEQKEY (int).

Какие у меня варианты улучшения производительности? Я слышал, что взгляды удобны, но не производительны. Должен ли я просто скопировать необходимые столбцы из таблицы A и B в одну таблицу, а затем выполнить приведенный выше запрос? У меня есть индексы в таблицах A и B на биржевом символе + дата (A) и DSEQKEY (B).

Это представление убивает мое выступление? Как я могу улучшить это?

EDIT

По запросу я разместил 2 таблицы и представление ниже. Кроме того, теперь существует один кластерный индекс для представления и каждой таблицы. Я открыт для любых рекомендаций, так как этот запрос, который дает желаемый результат, все еще медленный:

SELECT
      x.symbol
    , x.dseqkey
    , AVG(y.VOLUME) moving_average
FROM STOCK_HIST x
JOIN STOCK_HIST y ON x.dseqkey BETWEEN y.dseqkey AND y.dseqkey+29 AND Y.Symbol=X.Symbol
WHERE    x.dseqkey >= 15000
GROUP BY x.symbol, x.dseqkey
ORDER BY x.dseqkey DESC ;

ЗДЕСЬ ВИД:

CREATE VIEW [dbo].[STOCK_HIST]
WITH SCHEMABINDING
AS
SELECT
      dbo.DATE_MASTER.date
    , dbo.DATE_MASTER.year
    , dbo.DATE_MASTER.quarter
    , dbo.DATE_MASTER.month
    , dbo.DATE_MASTER.week
    , dbo.DATE_MASTER.wday
    , dbo.DATE_MASTER.day
    , dbo.DATE_MASTER.nday
    , dbo.DATE_MASTER.wkmax
    , dbo.DATE_MASTER.momax
    , dbo.DATE_MASTER.qtrmax
    , dbo.DATE_MASTER.yrmax
    , dbo.DATE_MASTER.dseqkey
    , dbo.DATE_MASTER.wseqkey
    , dbo.DATE_MASTER.mseqkey
    , dbo.DATE_MASTER.qseqkey
    , dbo.DATE_MASTER.yseqkey
    , dbo.DATE_MASTER.tom
    , dbo.QP_HISTORY.Symbol
    , dbo.QP_HISTORY.[Open]  as propen
    , dbo.QP_HISTORY.High    as prhigh
    , dbo.QP_HISTORY.Low     as prlow
    , dbo.QP_HISTORY.[Close] as prclose
    , dbo.QP_HISTORY.Volume
    , dbo.QP_HISTORY.QRS
FROM dbo.DATE_MASTER
INNER JOIN dbo.QP_HISTORY ON dbo.DATE_MASTER.date = dbo.QP_HISTORY.QPDate ;

ЗДЕСЬ ТАБЛИЦА ДАТЫ_MASTER:

CREATE TABLE [dbo].[DATE_MASTER] (
      [date]    [datetime] NULL
    , [year]    [int] NULL
    , [quarter] [int] NULL
    , [month]   [int] NULL
    , [week]    [int] NULL
    , [wday]    [int] NULL
    , [day]     [int] NULL
    , [nday]    nvarchar NULL
    , [wkmax]   [bit] NOT NULL
    , [momax]   [bit] NOT NULL
    , [qtrmax]  [bit] NOT NULL
    , [yrmax]   [bit] NOT NULL
    , [dseqkey] [int] IDENTITY(1,1) NOT NULL
    , [wseqkey] [int] NULL
    , [mseqkey] [int] NULL
    , [qseqkey] [int] NULL
    , [yseqkey] [int] NULL
    , [tom]     [bit] NOT NULL
) ON [PRIMARY] ;

ЗДЕСЬ ТАБЛИЦА QP_HISTORY:

CREATE TABLE [dbo].[QP_HISTORY] (
      [Symbol] varchar    NULL
    , [QPDate] [date]     NULL
    , [Open]   [real]     NULL
    , [High]   [real]     NULL
    , [Low]    [real]     NULL
    , [Close]  [real]     NULL
    , [Volume] [bigint]   NULL
    , [QRS]    [smallint] NULL
) ON [PRIMARY] ;

ЗДЕСЬ ИНДЕКС (STOCK_HIST)

CREATE UNIQUE CLUSTERED INDEX [ix_STOCK_HIST] ON [dbo].[STOCK_HIST]   
(
    [Symbol] ASC,  
    [dseqkey] ASC,  
    [Volume] ASC  
)

ЗДЕСЬ ИНДЕКС QP_HIST

CREATE UNIQUE CLUSTERED INDEX [IX_QP_HISTORY] ON [dbo].[QP_HISTORY] 
(
    [Symbol] ASC,
    [QPDate] ASC,
    [Close] ASC,
    [Volume] ASC
)

ЗДЕСЬ ИНДЕКС НА DATE_MASTER

CREATE UNIQUE CLUSTERED INDEX [IX_DATE_MASTER] ON [dbo].[DATE_MASTER] 
(
    [date] ASC,
    [dseqkey] ASC,
    [wseqkey] ASC,
    [mseqkey] ASC
)

У меня нет настроек первичных ключей. Поможет ли это производительность?

EDIT - После внесения предложенных изменений запрос выполняется медленнее, чем раньше. То, что бежало в 10 м 44 с, в настоящее время находится на 30 м и все еще работает.

Я сделал все запрошенные изменения, за исключением того, что я не изменил имя даты в Date_Master и не удалил столбец QPDate из QP_Hist. (У меня есть причины для этого, и я не вижу, как это влияет на производительность, поскольку я не ссылаюсь на это в запросе.)

ПЕРЕСМОТРЕННЫЙ ЗАПРОС

select x.symbol, x.dmdseqkey, avg(y.volume) as moving_average 
from dbo.QP_HISTORY as x
join dbo.QP_HISTORY as y on (x.dmdseqkey between y.dmdseqkey and (y.dmdseqkey + 29))                          
                         and (y.symbol = x.symbol)  
where x.dmdseqkey >= 20000 
group by x.symbol, x.dmdseqkey 
order by x.dmdseqkey desc ;

PK на QP_History

ALTER TABLE [dbo].[QP_HISTORY]
   ADD CONSTRAINT [PK_QP_HISTORY] PRIMARY KEY CLUSTERED ([Symbol] ASC, DMDSeqKey] ASC)

FK на QP_History

ALTER TABLE [dbo].[QP_HISTORY] ADD  CONSTRAINT [FK_QP_HISTORY_DATE_MASTER] FOREIGN KEY([DMDSeqKey]) REFERENCES [dbo].[DATE_MASTER] ([dseqkey])

PK на Date_Master

ALTER TABLE [dbo].[DATE_MASTER]
 ADD  CONSTRAINT [PK_DATE_MASTER] PRIMARY KEY CLUSTERED ([dseqkey] ASC)

РЕДАКТИРОВАТЬ

ЗДЕСЬ ПЛАН ИСПОЛНЕНИЯ

Ответы [ 4 ]

4 голосов
/ 26 января 2011

Сначала отдельное объединение фильтра.

(редактировать: исправлено предложение ON)

SELECT x.symbol, x.dseqkey, AVG(y.VOLUME) moving_average
FROM
    STOCK_HIST x
    JOIN
    STOCK_HIST y ON x.dseqkey BETWEEN y.dseqkey AND y.dseqkey+29
                                AND Y.Symbol=X.Symbol 
WHERE x.dseqkey>=29
GROUP BY x.symbol, x.dseqkey
ORDER BY x.dseqkey DESC

Кроме того, какие у вас индексы - я бы предложил индекс для (dseqkey, символ) ВКЛЮЧИТЬ (ОБЪЕМ)

Редактировать 3: у вас не может быть ВКЛЮЧЕНО в кластерный индекс, мой плохой. Ваш синтаксис в порядке.

Пожалуйста, попробуйте эти перестановки ... цель состоит в том, чтобы найти лучший индекс для JOIN и WHERE, а затем ORDER BY.

CREATE UNIQUE CLUSTERED INDEX [ix_STOCK_HIST] ON [dbo].[STOCK_HIST] (...

    ...[Symbol] ASC, [dseqkey] ASC, [Volume] ASC )

    ...[dseqkey] ASC, [Symbol] ASC, [Volume] ASC )

    ...[Symbol] ASC, [dseqkey] DESC, [Volume] ASC )

    ...[dseqkey] DESC, [Symbol] ASC, [Volume] ASC )
3 голосов
/ 26 января 2011

SQL Server не поддерживает предложения LAG или LEAD, доступные в Oracle и PostgreSQL, а также не поддерживает переменные сеанса, такие как MySQL.

Расчет агрегатов по движущимся окнам - боль в SQL Server.

Итак, Бог знает, что мне неприятно это говорить, однако в этом случае решение на основе CURSOR может быть более эффективным.

1 голос
/ 26 января 2011

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

, что должно немного ускорить процесс.

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

0 голосов
/ 27 января 2011

ОК, так что я начну с конца.Я хотел бы достичь этой модели.

enter image description here

Имея это, вы можете выполнить запрос к таблице истории напрямую, без необходимости просмотра и присоединиться к dbo.DATE_MASTER.

select
      x.symbol
    , x.dseqkey
    , avg(y.volume) as moving_average
from dbo.QP_HISTORY as x
join dbo.QP_HISTORY as y on  (x.dSeqKey between y.dSeqKey and (y.dSeqKey + 29))
                         and (y.symbol = x.symbol) 
where x.dseqkey >= 15000
group by x.symbol, x.dseqkey
order by x.dseqkey desc 
OPTION (ORDER GROUP) ;

QP_HISTORY уже, чем STOCK_HISTORY, поэтому запрос должен быть быстрее.«Избыточное удаление столбцов» из объединений запланировано для следующего поколения SQL Server (Denali), поэтому в настоящее время его сужение обычно означает ускорение - по крайней мере, для больших таблиц.Кроме того, предложения join on .. и where хорошо совпадают с PK(Symbol, dSeqKey).

Теперь, как этого добиться:

a) Измените столбец [date] в dbo.DATE_MASTER быть, если тип date вместо datetime.Переименуйте его FullDate, чтобы избежать путаницы.Не абсолютно необходимо, но для сохранения моего здравомыслия.

b) Добавьте PK к dbo.DATE_MASTER

alter table dbo.DATE_MASTER add constraint primary key pk_datemstr (dSeqKey);

c) В таблице QP_HISTORY добавьте столбец dSeqKey и заполните егодля сопоставления QPDate дат.

d) Удалить столбец QPDate из таблицы.

e) Добавить PK и FK в QP_HISTORY

alter table dbo.QP_HISTORY
   add constraint pk_qphist  primary key (Symbol, dSeqKey)
 , add constraint fk1_qphist foreign key (dSeqKey)
                             references dbo.DATE_MASTER(dSeqKey) ;

f) Отбросьте все те индексы, которые указаны в конце вашего вопроса, по крайней мере, на данный момент.

g) Я не вижу размера поля Symbol.Определите его как можно более узким.

h) Сначала нужно сказать, внедрить и протестировать это в системе разработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...