Использование SUM () дважды неоптимально?


8

Я знаю, что должен написать SUMдважды, если я хочу использовать его в HAVINGпредложении (или использовать производную таблицу в противном случае):

SELECT  id,
  sum(hours) AS totalhours
  FROM mytable
  GROUP BY id
  HAVING sum(hours) > 50;

Мой вопрос сейчас заключается в том, является ли это неоптимальным. Как программист, этот запрос выглядит так, как будто БД рассчитает сумму дважды. Это так, или я должен полагаться на оптимизацию, которую мне сделает механизм БД?

Обновление: объяснение сопоставимого запроса:

postgres=> explain select sum(counttodo) from orderline group by orderlineid having sum(counttodo) > 100;
                             QUERY PLAN                             
--------------------------------------------------------------------
 HashAggregate  (cost=1.31..1.54 rows=18 width=8)
   Filter: (sum(counttodo) > 100)
   ->  Seq Scan on orderline  (cost=0.00..1.18 rows=18 width=8)
(3 rows)

Вы можете опубликовать объяснение?
Ste

Я не буду отвечать на это как есть хороший, краткое объяснение здесь : "В случае , если вам интересно , почему вы не можете обратиться к SELECT , псевдонимами позже в запросе, например , в ИНЕКЕ, все это делать с заказом SQL не оценивается в том порядке, в котором он написан. Список SELECT фактически вычисляется почти последним, а его содержимое фактически еще не существует, когда обрабатываются HAVING и т. д. Это становится важным, когда список выбора включает функции с побочные эффекты [...] "
Дезсо

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

2
@BartFriederichs хорошо, многие люди жалуются на эти строки (я тоже жаловался, пока не привык к этому ...) Это не выполняется дважды и, вероятно, может быть выполнено с использованием псевдонима в HAVING(а затем извлечение определения столбца из SELECTпункта) - по какой-то причине они просто не делают этого.
Дезсо

3
Я думаю, что позволить механизму БД беспокоиться об оптимизации должно быть второй натурой для специалиста по СУБД. SQL - это 4GL, поэтому мы определяем желаемый набор результатов, а не средства, с помощью которых он достигается. Есть много других проблем, о которых мы по большей части не беспокоимся - например, порядок соединения или преобразование EXISTS в соединение. Эта конкретная проблема в большей степени является проблемой с точки зрения «Не повторяйся» для сложных выражений, но разумные обходные пути (встроенные представления, CTE) могут помочь с этим.
Дэвид Олдридж

Ответы:


3

Сумма рассчитывается только один раз.

Я подтвердил это с помощью

create table mytable (id int, hours int);
insert into mytable values (1, 60);
select sum(hours) from mytable group by id having sum(hours) > 50;

и затем использовал отладчик, чтобы проверить, сколько раз int4_sum(функция перехода за sumагрегатом) была вызвана: один раз.


0

Сравните ваш запрос

explain
select sum(counttodo)
from orderline
group by orderlineid
having sum(counttodo) > 100

К этому эквивалентному чеку, чем они отличаются

explain
select *
from (
    select sum(counttodo) counttodo
    from orderline
    group by orderlineid
) s
where counttodo > 100

1
Я вижу, к чему вы клоните, но в его нынешнем виде это не дает «хорошего» ответа. Опубликуйте объяснение для каждого с небольшим количеством комментариев, и вы будете хороши для некоторых голосов.
Марк Стори-Смит

0

Вам не нужно писать SUMдважды, если вам не нужно получать его; если вас интересуют только те, у idкоторых есть a, SUM(hours) > 50то совершенно верно следующее:

SELECT id,
FROM mytable
GROUP BY id
HAVING sum(hours) > 50;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.