подзапросы SQL в CASE WHEN выполняются один раз для запроса или для каждой строки?

В принципе, является ли приведенный ниже код эффективным (если я не могу использовать переменные @ в MonetDB), или он будет вызывать подзапросы более одного раза каждый?

CREATE VIEW sys.share26cuts_2007 (peorglopnr,share26cuts_2007) AS (
SELECT peorglopnr, CASE WHEN share26_2007 < (SELECT QUANTILE(share26_2007,0.25) FROM sys.share26_2007) THEN 1
                        WHEN share26_2007 < (SELECT QUANTILE(share26_2007,0.5) FROM sys.share26_2007) THEN 2
                        WHEN share26_2007 < (SELECT QUANTILE(share26_2007,0.75) FROM sys.share26_2007) THEN 3
                        ELSE 4 END AS share26cuts_2007
FROM sys.share26_2007
);

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


person László    schedule 12.06.2014    source источник
comment
Я знаю, что оператор CASE будет выполняться один раз для каждой строки в SQLServer, но я понятия не имею о monetdb.   -  person user2989408    schedule 12.06.2014
comment
Уверен, что вы захотите сохранить эти значения QUANTILE() в таблице, чтобы они не вычислялись несколько раз.   -  person Hart CO    schedule 12.06.2014
comment
@user2989408 user2989408 Спасибо, но, по крайней мере, для SQLServer то, что вы говорите, будет означать, что в подзапросе нет кэширования, ничто не распознает, что это одно и то же?   -  person László    schedule 12.06.2014
comment
@GoatCO Я был бы признателен за помощь в том, что вы имеете в виду, как я могу ссылаться на эти сохраненные значения в запросе. Я с радостью приму ваш ответ, если вы его напишете!   -  person László    schedule 12.06.2014
comment
Я бы использовал План выполнения, чтобы ответить на этот вопрос и сравнить общую стоимость испытаний.   -  person BI Dude    schedule 12.06.2014
comment
@TadasV Спасибо, я не думаю, что это доступно в MonetDB.   -  person László    schedule 12.06.2014
comment
@BIDude Я не думаю, что это доступно в MonetDB.   -  person László    schedule 12.06.2014
comment
Я сделал вывод отсюда в ответ, но, к сожалению, есть и другие ошибки с квантилями.   -  person László    schedule 13.06.2014


Ответы (2)


Как например. GoatCO прокомментировал вопрос, этого, вероятно, лучше избегать. Команду SET, которую поддерживает MonetDB, можно использовать с SELECT, как показано в приведенном ниже коде. Остается вопрос, почему все квантили равны нулю, а мои данные точно нет (я также получил ошибки деления на ноль до использования NULLIF). Сейчас я покажу больше кода.

CREATE VIEW sys.over26_2007 (personlopnr,peorglopnr,loneink,below26_loneink) AS (
SELECT personlopnr,peorglopnr,loneink, CASE WHEN fodelsear < 1981 THEN 0 ELSE loneink END AS below26_loneink
FROM sys.ds_chocker_lev_lisaindivid_2007
);
SELECT COUNT(*) FROM over26_2007;

CREATE VIEW sys.share26_2007 (peorglopnr,share26_2007) AS (
SELECT peorglopnr, SUM(below26_loneink)/NULLIF(SUM(loneink),0)
FROM sys.over26_2007
GROUP BY peorglopnr
);
SELECT COUNT(*) FROM share26_2007;

DECLARE firstq double;
SET firstq = (SELECT QUANTILE(share26_2007,0.25) FROM sys.share26_2007);
SELECT firstq;
DECLARE secondq double;
SET secondq = (SELECT QUANTILE(share26_2007,0.5) FROM sys.share26_2007);
SELECT secondq;
DECLARE thirdq double;
SET thirdq = (SELECT QUANTILE(share26_2007,0.275) FROM sys.share26_2007);
SELECT thirdq;
CREATE VIEW sys.share26cuts_2007 (peorglopnr,share26cuts_2007) AS (
SELECT peorglopnr, CASE WHEN share26_2007 < firstq THEN 1
                        WHEN share26_2007 < secondq THEN 2
                        WHEN share26_2007 < thirdq THEN 3
                        ELSE 4 END AS share26cuts_2007
FROM sys.share26_2007
);
SELECT COUNT(*) FROM share26cuts_2007;
person László    schedule 12.06.2014

Что касается проверки планов, MonetDB поддерживает:

  • ПЛАН, чтобы увидеть логический план
  • EXPLAIN, чтобы увидеть физический план с точки зрения MAL инструкции
  • TRACE аналогично EXPLAIN, но фактически выполняет план MAL и возвращает статистику для всех инструкций .

Что касается вашего вопроса о повторении подзапросов, в принципе ничего повторяться не будет, и вам не нужно будет об этом явно заботиться. Это связано с тем, что конвейер оптимизации по умолчанию включает оптимизатор commonTerms. Ваш SQL будет преобразован в последовательность инструкций MAL с повторяющимися вызовами. MAL спроектирован так, чтобы быть простым: множество коротких вызовов инструкций, немного похожих на ассемблер, которые работают со столбцами, а не со строками (поэтому не применяйте те же рассуждения, которые вы использовали бы для SQL Server, когда думаете о эффективность исполнения). Это упрощает выполнение некоторых оптимизаций. Оптимизатор commonTerms обнаружит повторяющиеся вызовы и повторно использует все возможные результаты. Это делается для каждого столбца. Таким образом, вы действительно сможете выполнить свой запрос и быть счастливым.

Однако я сказал в принципе. Не все случаи будут обнаружены (хотя большинство будет), плюс некоторые ограничения были введены намеренно. Например, область поиска для обнаружения дубликатов — это окно (слишком маленькое, на мой вкус — я вообще убрал его в своих инсталляциях) по всему плану MAL: если дублирующаяся инструкция находится слишком далеко в плане, она не будет обнаружено. Это было сделано для эффективности. В вашем случае этот отдельный запрос не такой большой, но если он является частью более длинной цепочки представлений, то все эти представления будут скомпилированы в большой план MAL, который может сделать commonTerms менее эффективным. - это действительно зависит от реальных запросов.

person cornuz    schedule 11.10.2014