Я думал об этом несколько дней назад после оптимизации SQL. Я думаю, что мы можем согласиться с тем, что SQL является «декларативным языком» в определении Википедии:
Парадигма программирования, выражающая логику вычислений без описания потока управления
Если вы думаете, сколько всего сделано за кулисами (просматривая статистику, решая, является ли индекс полезным, переходя к вложенному, объединенному или хеш-соединению и т. Д. И т. Д.), Мы должны признать, что мы даем просто высокий уровень логика, и база данных позаботилась обо всей логике управления потоком низкого уровня.
Также в этом сценарии иногда оптимизатору базы данных требуются некоторые «подсказки» от пользователя, чтобы дать наилучшие результаты.
Другое распространенное определение «декларативного» языка: (Я не могу найти авторский источник):
Парадигма программирования, которая выражает желаемый результат вычислений без описания шагов для его достижения (также сокращенно «опишите что, а не как»)
Если мы примем это определение, мы столкнемся с проблемами, описанными ФП.
Первая проблема заключается в том, что SQL дает нам несколько эквивалентных способов определения «одного и того же результата». Возможно, это неизбежное зло: чем больше выразительной силы мы даем языку, тем больше у него может быть разных способов выразить одно и то же.
Как пример, меня однажды попросили оптимизировать этот запрос:
SELECT Distinct CT.cust_type, ct.cust_type_description
from customer c
INNER JOIN
Customer_type CT on c.cust_type=ct.cust_type;
Так как типы были намного меньше, чем у клиента, и cust_type
на таблице клиентов был индекс , я добился значительного улучшения, переписав его так:
SELECT CT.cust_type, ct.cust_type_description
from Customer_type CT
Where exists ( select 1 from customer c
Where c.cust_type=ct.cust_type);
В этом конкретном случае, когда я спросил разработчика, чего он хочет достичь, он сказал мне: «Мне нужны все типы клиентов, для которых у меня был хотя бы один клиент», именно так можно описать запрос оптимизатора.
Итак, если бы я мог найти эквивалентный и более эффективный запрос, почему оптимизатор не может сделать то же самое?
Я думаю, что это по двум основным причинам:
SQL выражает логику:
поскольку SQL выражает высокоуровневую логику, хотим ли мы, чтобы оптимизатор «перехитрил» нас и нашу логику? Я бы с энтузиазмом кричал «да», если бы не все времена, когда мне приходилось заставлять оптимизатор выбирать наиболее эффективный путь выполнения. Я думаю, что идея могла бы состоять в том, чтобы позволить оптимизатору делать все возможное (также пересматривая нашу логику), но дать нам «механизм намека», чтобы прийти на помощь, когда что-то сходит с ума (это было бы похоже на колесо + тормоза в автономный автомобиль).
Больше вариантов = больше времени
Даже самый лучший оптимизатор СУБД не тестирует ВСЕ возможные пути выполнения, поскольку они должны быть очень быстрыми: насколько хорошо было бы оптимизировать запрос от 100 мс до 10 мс, если бы мне приходилось каждый раз тратить 100 мс на выбор наилучшего пути? И это с оптимизатором, уважающим нашу «логику высокого уровня». Если он также должен протестировать все эквивалентные запросы SQL, время оптимизатора может возрасти в несколько раз.
Еще один хороший пример переписывания запросов, который фактически может выполнить ни одна СУБД (из этого интересного сообщения в блоге )
SELECT t1.id, t1.value, SUM(t2.value)
FROM mytable t1
JOIN mytable t2
ON t2.id <= t1.id
GROUP BY t1.id, t1.value;
чем можно написать как это (аналитические функции требуются)
SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
FROM mytable
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
, Это должно быть тривиально, чтобы увидеть, как повторить это с помощьюexists
илиjoin
.