SQL Server Cross Apply сам по себе + проблемы с производительностью Cross Apply

У меня есть следующее:

CREATE TABLE #MASTER_POSANDTRANS (ID CHAR(30), 
                                  QUANTITY INT, 
                                  START_OR_TRADE_DATE DATE) 

VALUES 
    ('APPLES ','150000','20150501'), ('PEARS','220000','20150501'), 
    ('APPLES ','-75000','20150506'), ('APPLES ','-65000','20150508'), 
    ('APPLES ','10000','20150516'),  ('APPLES ','-20000','20150519'
    ('PEARS','-110000','20150506'),  ('PEARS','-100000','20150519')

Я хочу иметь возможность сказать: «Хорошо, вначале у меня было 150 000 яблок, поэтому моя общая позиция по яблокам была ДЛИННОЙ».

Вот как я сейчас решаю эту маленькую головоломку:

SELECT 
    MPT.ID, 
    MPT.QUANTITY, 
    MPT.START_OR_TRADE_DATE, 
    APPLY_RES.QUANTITY as 'FIRST AVAILABLE  QUANTITY', 
    CASE 
       WHEN APPLY_RES.QUANTITY > 0 
         THEN 'LONG' 
         ELSE 'SHORT' 
    END as 'L/S Indicator'
FROM 
    #MASTER_POSANDTRANS as MPT 
CROSS APPLY
    (SELECT TOP 1 
         MPT_APPLY.QUANTITY 
     FROM 
         #MASTER_POSANDTRANS as MPT_APPLY
     WHERE 
         MPT_APPLY.ID = MPT.ID) APPLY_RES

Представленная таблица представляет собой упрощенный результат нескольких запросов и объединений, которые выдают около 387 строк примерно за 3 секунды. Однако, когда я пытаюсь применить свое решение к этому результату из 387 строк, мой запрос возвращает правильный результат, но занимает 21 секунду вместо 3.

Есть предложения по улучшению?

Еще немного к головоломке:

  1. Первая доступная «транзакция» решает, буду ли я играть в длинную или короткую позицию.

  2. Другая, более сложная проблема (для тех, кто любит головоломки) состоит в том, чтобы взять средневзвешенный холдинг, чтобы решить, был ли я в длинной или короткой позиции в течение периода. Например, представьте, что после последней сделки с яблоками 19-го числа, когда у меня осталось 0 яблок, я продал еще 1 миллион яблок. Это означало бы, что с 19 по 31 мая у меня не было 1 миллиона. (31-19) * -1 000 000 ‹ (19-1)*(Среднее количество проданных/купленных яблок в течение месяца), следовательно, мое владение яблоками в этом месяце можно считать коротким. Если бы в какой-то момент они уравновесились, я бы взял значение в точке 1.


person buellboy    schedule 03.08.2015    source источник
comment
Какой SQL-сервер вы используете?   -  person Mike Miller    schedule 03.08.2015
comment
Пакет обновления 2 для SQL Server 2008 R2 10.50.4000   -  person buellboy    schedule 03.08.2015
comment
Запустите SQL Fiddle, похоже, это не дает желаемого результата... sqlfiddle .com/#!3/ea1c3/1/0   -  person SQL Tactics    schedule 03.08.2015
comment
Спасибо за ссылку. Это довольно крутая штука! Я посмотрел, полученные результаты верны. Я купил 150 000 яблок в начале месяца (или в первую доступную дату транзакции за май), поэтому все последующие транзакции яблок помечены как длинные. То же самое с грушами (220 000 была первой транзакцией, поэтому все остальные транзакции отмечены как длинные)   -  person buellboy    schedule 04.08.2015
comment
Редактировать: я должен перефразировать: Хорошо, в начале у меня было 150 000 яблок, поэтому моя общая позиция яблока была ДЛИННОЙ до Хорошо, в начале у меня было 150 000 яблок, поэтому мое общее яблоко за период времени было ДЛИННЫМ, поэтому все транзакции (+ve или -ve) должен иметь маркер LONG   -  person buellboy    schedule 04.08.2015


Ответы (1)


You Cross Apply Select отсутствует Order By (дата?). Это не детерминировано, и нет никакой гарантии, что вы действительно получите 1-ю запись.

Для ваших выборочных данных этот запрос имеет лучший план запроса:

SELECT
    MPT.ID,
    MPT.QUANTITY,
    MPT.START_OR_TRADE_DATE
    , APPLY_RES.QUANTITY as 'FIRST AVAILABLE  QUANTITY',
    CASE
    WHEN APPLY_RES.QUANTITY > 0
        THEN 'LONG'
    ELSE 'SHORT'
    END as 'L/S Indicator'
From MASTER_POSANDTRANS AS MPT
Inner Join (
    Select ID, QUANTITY, N = ROW_NUMBER() over (Partition by ID order by START_OR_TRADE_DATE)
    From MASTER_POSANDTRANS
) as APPLY_RES on APPLY_RES.ID = MPT.ID
Where APPLY_RES.N = 1
--Order By MPT.ID, MPT.START_OR_TRADE_DATE 
person Julien Vavasseur    schedule 10.08.2015