Я спрашиваю, потому что многие вопросы, которые я вижу в SQL, сводятся к следующему: «Это медленно. Как мне это ускорить»? Или учебники, в которых говорится: «Делай так, а не так, потому что это быстрее».
Мне кажется, что большая часть SQL знает, как будет выполняться выражение, и из этого знания выбирает стили выражения, которые работают лучше. Это не согласуется с одним аспектом декларативного программирования - с тем, чтобы система сама решала, как наилучшим образом выполнить вычисления, просто указав, что должно произвести вычисление.
Разве движок SQL не должен заботиться о том, что вы используете in
, exists
или join
он действительно декларативный, не должен ли он дать вам правильный ответ в разумные сроки, если это возможно, любым из трех методов? Этот последний пример вызван недавним сообщением того типа, который упоминается в моем первом абзаце.
Индексы
Я предполагаю, что самый простой пример, который я мог бы использовать, связан с созданием индекса для таблицы. Гимф здесь на w3schools.com даже пытается объяснить это как что-то невидимое пользователем, которое существует по соображениям производительности. Похоже, что их описание помещает индексы SQL в недекларативный лагерь, и они обычно добавляются вручную из чисто соображений производительности.
Это тот случай, когда они являются идеальной базой данных SQL, которая гораздо более декларативна, чем все остальные, но потому, что это хорошо, что никто не слышит об этом?
источник
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
, Это должно быть тривиально, чтобы увидеть, как повторить это с помощьюexists
илиjoin
.Ответы:
SQL теоретически декларативен. Но вы знаете, что они говорят о разнице между теорией и практикой ...
По своей сути концепция «декларативного программирования» никогда не была по-настоящему эффективной, и, вероятно, никогда не будет, пока у нас не будет AI-компилятора, который способен смотреть на код и отвечать на вопрос «каково намерение этого кода?» разумно, так же, как и тот, кто это написал. В основе каждого декларативного языка лежит целый набор императивного кода, который отчаянно пытается решить эту проблему без помощи ИИ.
Часто это работает на удивление хорошо, потому что наиболее распространенные случаи - это обычные случаи , о которых люди, написавшие реализацию языка, знали и находили хорошие способы их обработки. Но затем вы сталкиваетесь с крайним случаем, который разработчик не учел, и вы видите, что производительность быстро падает, поскольку интерпретатор вынужден воспринимать код гораздо более буквально и обрабатывать его менее эффективно.
источник
I rarely hit an edge case in any of them that couldn't be solved within the framework.
Да, в этом весь смысл: нужно искать способ их решения в рамках структуры, потому что структура недостаточно умна, чтобы решить ее для вас так, как вы первоначально объявили ее.Я думал об этом несколько дней назад после оптимизации SQL. Я думаю, что мы можем согласиться с тем, что SQL является «декларативным языком» в определении Википедии:
Если вы думаете, сколько всего сделано за кулисами (просматривая статистику, решая, является ли индекс полезным, переходя к вложенному, объединенному или хеш-соединению и т. Д. И т. Д.), Мы должны признать, что мы даем просто высокий уровень логика, и база данных позаботилась обо всей логике управления потоком низкого уровня.
Также в этом сценарии иногда оптимизатору базы данных требуются некоторые «подсказки» от пользователя, чтобы дать наилучшие результаты.
Другое распространенное определение «декларативного» языка: (Я не могу найти авторский источник):
Если мы примем это определение, мы столкнемся с проблемами, описанными ФП.
Первая проблема заключается в том, что SQL дает нам несколько эквивалентных способов определения «одного и того же результата». Возможно, это неизбежное зло: чем больше выразительной силы мы даем языку, тем больше у него может быть разных способов выразить одно и то же.
Как пример, меня однажды попросили оптимизировать этот запрос:
Так как типы были намного меньше, чем у клиента, и
cust_type
на таблице клиентов был индекс , я добился значительного улучшения, переписав его так:В этом конкретном случае, когда я спросил разработчика, чего он хочет достичь, он сказал мне: «Мне нужны все типы клиентов, для которых у меня был хотя бы один клиент», именно так можно описать запрос оптимизатора.
Итак, если бы я мог найти эквивалентный и более эффективный запрос, почему оптимизатор не может сделать то же самое?
Я думаю, что это по двум основным причинам:
SQL выражает логику:
поскольку SQL выражает высокоуровневую логику, хотим ли мы, чтобы оптимизатор «перехитрил» нас и нашу логику? Я бы с энтузиазмом кричал «да», если бы не все времена, когда мне приходилось заставлять оптимизатор выбирать наиболее эффективный путь выполнения. Я думаю, что идея могла бы состоять в том, чтобы позволить оптимизатору делать все возможное (также пересматривая нашу логику), но дать нам «механизм намека», чтобы прийти на помощь, когда что-то сходит с ума (это было бы похоже на колесо + тормоза в автономный автомобиль).
Больше вариантов = больше времени
Даже самый лучший оптимизатор СУБД не тестирует ВСЕ возможные пути выполнения, поскольку они должны быть очень быстрыми: насколько хорошо было бы оптимизировать запрос от 100 мс до 10 мс, если бы мне приходилось каждый раз тратить 100 мс на выбор наилучшего пути? И это с оптимизатором, уважающим нашу «логику высокого уровня». Если он также должен протестировать все эквивалентные запросы SQL, время оптимизатора может возрасти в несколько раз.
Еще один хороший пример переписывания запросов, который фактически может выполнить ни одна СУБД (из этого интересного сообщения в блоге )
чем можно написать как это (аналитические функции требуются)
источник