Comments 51
Мой аргумент — это то чтобы дополнить такой запрос на 2 экрана, надо потратить от получаса времени, чтобы разобраться как он и почему работает и как его исправить. И это надо будет делать КАЖДЫЙ раз при встрече с таким запросом. И протестировать его и отладить по частям неудобно. И план запроса по такой бандуре сложен и непонятен.
WHERE '2017-01-02'::date - 7 <= arrival_date AND arrival_date <= '2018-01-02'::date + 7
Весьма странное место. Зачем нужно проверять даты за год назад?
Когда у вас мало пользователей, то да, вообще никаких проблем. А они возникнут ровно тогда, когда их количество увеличится, и скажем, у вас будут постоянные локи на таблицы. Что вы будете делать тогда с запросом, который будет из-за этого адово тупить?
Я так же напомню, что в postgres даже нет грязного чтения, только repetable read.
С одной стороны на одном и том же железе получился прирост производительности, с другой стороны его решение не оптимально и требует доработки
Тот же самый birt-viewer все отчеты строит в БД, потому что он оперирует полученными данными для отображения
И вы серьезно думаете, что например Java медленнее чем pgSQL?
Вы путаете мягкое с тёплым
Во-первых, sql выполняет именно то для чего он создан, запросы к бд
Во-вторых, приложению сначала надо получит данные из бд, а потом уже с ними выполнять некие действия
В-третьих, мы все знаем что Java очень любит память
Для текущего решения делать выборку средствами БД самое разумное. Но никто не отменял оптимизацию запросов и индексирования таблиц
— при выполнении можно зачитать данные только из индекса (например для выполнения exists
— не произойдет конфликта согласованности данных только если вы не используете уровень изоляции serializable что дорого
— у базы есть статистика о кардинальности связей и она может применя разные
алгоримы для соединения таблиц
— база кеширует данные таблиц и индексов в памяти
Это просто 4 фактора что на вскидку в голову пришли.
В итоге чтении данных потребуется меньше операций чтения с диска (что на самом деле является единственной проблемой при чтении как в задаче с поиском) причем меньше не в константу раз а лучше.
А нет, это я читаю не тем местом.
А поясните, что значит версии не восстанавливаются и почему чтение радикально дешевле чем в оракле? В оракле есть три уровня изоляции и в пг вроде тоже read commited read dirty и serializable
Третий реально требует поиска блока нужной версии в анду, а read committed позволяет просто найти оригинальную версию блока в анду причем его адрес в самом блоке и записан так что там небольшие потери. А как постгрес действует?
Я бы поднял Solr/ElasticSearch c денормализованными данными, оптимизированными под нужный вид поиска.
Быть может, это было бы больше кода, связанного с обновлением поискового индекса, но решение точно получилось бы проще и масштабировалось бы лучше.
Проблема вашего решения в наличии связи между бизнес-требованиями и структурой базы. Это проблемно, т.к.
- при изменении требований возможно придется делать несовместимую миграцию базы (долго и даунтайм)
- может появиться рассинхрон между данными и производными полями. У поискового индекса такой проблемы нет, т.к. его можно быстро перестроить.
- народ может повадиться делать селекты не по данным, а по производным полям, добавленным для поиска. Это значительно увеличит хрупкость системы.
Трудоемкость — это довод, если умеете лепить хитрые запросы и не умеете в индекс. Но на вашем месте я бы как минимум вынес производные поля как минимум в отдельные таблицы.
Почему было не написать логику в Stored Procedure? Ведь тогда этого монитра можно было бы побить на куски, которые человек был бы способен понять.
На деле он строится из кусков, это всего лишь несколько CTE следующие друг за другом. И в приложении каждое CTE строится отдельно, и более того, они переиспользуются в других подобных запросах.
И если рассматривать запрос отдельно, по шагам, как в статье, то ничего страшного в нем нет.
И чем же хранимая процедура упростит внесение изменений или поиск багов? На куски можно побить и в коде приложения с ровно таким же успехом.
А как обойтись без DISTINCT если нужны уникальные записи?
WITH RECURSIVE t AS (
(SELECT min(val) AS val FROM test)
UNION ALL
SELECT (SELECT min(val) FROM test WHERE val > t.val)
AS val FROM t WHERE t.val IS NOT NULL
)
SELECT val FROM t WHERE val IS NOT NULL;
(Автор данного запроса Максим Богук.)
Хм, интересно. Я полный нуб в Postgres, не знал что можно так, спасибо
Cила PostgreSQL