Комментарии 21
Однажды я поступил в универ на бюджет (математическая специальность), как потом выяснилось, решив задачу неправильно! После экзамена перерешал и понял где закралась ошибка. Сразу расстроился, думая что не поступил, т.к. без той задачи я уже не проходил по баллам. Но случилось странное как мне казалось тогда чудо - проверяющие почти не срезали за него баллы, т. к. в принципе правильных рассуждений в нём было достаточно много. Мораль, думаю, понятна.
вместе с заданием шел скрипт наполнения таблицы тестовыми данными, который я тут приводить не буду. Он основан на функции random и всё время будет выдавать разный набор.
Совершенно напрасно. Пусть не воспроизведётся один к одному ваш набор записей. но тенденции останутся практически неизменными. Миллиона записей достаточно, чтобы их выровнять. Опять же всегда можно перегенерировать набор (несколько раз, или расширить его) и повторить - общее останется, а случайные выбросы уйдут. А сейчас - голые слова.
Но постойте, ведь в задании сказано, что
Сообщения обрабатываются в порядке возрастания значения поля “process_date“.
Здесь же получается, что 3-е число еще не обработано, 4-ое обработано, а 5-ое снова не обработано.
Странно все это подумал я и решил, что данный факт просто опишу в решении.
Что вы нашли странного? То, что сообщение взято на обработку, не означает, что оно будет обработано ранее более позднего. Как и не означает, что оно будет обработано вообще. Вполне себе нормальная ситуация, которую вы почему-то решили проигнорировать. так что ответ про "несостыковки по части логики" - совершенно справедливо.
использование бесполезного rows only и fetch вместо limit.
Документация PostgreSQL практически открытым текстом говорит, что LIMIT и FETCH - это разные синтаксические формы одной и той же операции. SQL:2008 ввёл, Postgres взял под козырёк - и не более. В чём вы видите различие в полезности?
В задании ничего не сказано про специфику обработки. А я уж поверьте наелся очередей и прекрасно понимаю, что могут быть дырки.
Если читать мою статью внимательно, то у меня есть вариант, который это учитывает.
Про скрипт. Мне не хотелось выкладывать задание полностью. По понятным надеюсь причинам
FETCH в продакшене не видел ни разу, потому что есть новый limit
Это какой такой "новый"? Тот, который общеизвестен, появился гораздо раньше FETCH, уж в Постгрессе-то точно, так что это по сравнению с ним FETCH - новый.
Итак. fetch имеет смысл только with ties, который тут не нужен. Я, конечно, пошел и перечитал. Не уверен я, что даже вы прям все-все детали документации помните. Но суть моей статьи вообще не в этом. Вы б лучше, что-нибудь по делу сказали, чем цепляться за мелочи.
Не уверен я, что даже вы прям все-все детали документации помните.
Не поверите, но я, прежде, чем писать, тоже сначала освежил память чтением документации. И даже пробежался по изменениям в версиях.
Вы б лучше, что-нибудь по делу сказали
Вы проигнорировали особенности набора данных. У вас же вся статья построена на "у вас неправильный набор данных, я его поправлю, а потом буду решать". Я ничего не имею против ваших вариантов решения - кроме того, что они решают ДРУГУЮ задачу.
Опять же - вы смело вмешиваетесь в данные: "При этом сделал число 2026-01-04 не обработанным". Сразу возникает вопрос, почему вы столь же смело не вмешались в структуру? Так, как предложил @NeKukSA. На поверхности же плавает..
Нет, я понимаю, что вам обидно. Рассказываете в общем хорошую вещь, а вам тычут в несоблюдение условий. Но ведь оно - имеется, из песни слова не выбросишь.
Т.е. если запрос ничего не вернул, значит этот день полностью обработан и рекурсия останавливается.
А если имеется день без записей? Я не вижу в задании, что это невозможно. Этой возможности ваше первое решение, то, что с рекурсией, не учитывает.
Итак. fetch имеет смысл только with ties, который тут не нужен.
WITH TIES - это дополнительная, и да, весьма небесполезная, фича, но никто не обязывает ей пользоваться. А без неё LIMIT и FETCH - это по факту синонимы в PostgreSQL. И слышать, что решение, имеет или не имеет смысл конкретная операция, принимается на основании её синтаксической формы - несколько странно.
Вы проигнорировали особенности набора данных
Я хочу вас спросить. Вы видели запрос с рекурсией? Понимаете, чем он отличается от того для которого потребовалось изменить данные? Понимаете, что эти запросы вернут одно и то же? Я только до сих пор не понимаю, как действует мнимый обработчик. Поэтому варианта основных два.
А если имеется день без записей?
А если кто-то другой загребет ту же запись? Тоже как бы по заданию можно предположить?
А если обработает, а признак не вернёт? Тоже по заданию...
Можно вас попросить проголосовать за неточность ТЗ?
Но ведь оно - имеется, из песни слова не выбросишь.
Там надо ускорить запрос, а не писать реальную очередь.
Не делал дополнительных и супер очевидных индексов только потому что в задании сказано изменить запрос. Изменить САМ запрос, чтобы он стал быстрей. Да и как вы, вероятно уже поняли, индексы нужно было не создавать, а убивать :) И последнее. Работа была 100% такая, что решение ускорить запрос индексом железобетонно не прокатило бы. Слишком уж просто.
Ну и кстати, в решении которое я им послал в пунктах ниже, были и индексы, и инклуды и даже партиции. Согласитесь, с партициями и индексы не нужны. Но все это было проигнорировано.
WITH TIES
Бог с ним. По настоящему это отношение к делу не имеет.
А почему не создать подходящий для запроса индекс? Копия уже имеющегося с условием
where status <> '10782572'::numeric
Индекс всегда будет содержать ссылки только на актуальные для шедулера строки, не будет занимать много памяти и не будет распухать при условии, что строки будут своевременно обрабатываться и автовакуум на базе не выключен)
Я бы начал разговор именно с такого предложения, даже выдумывать ничего не стал бы с запросом. Индексы - такой же инструмент, чего бы им не пользоваться.
Вы, конечно совершенно правы! Такой индекс всегда будет "в форме".
Но, в задании написано изменить сам запрос. И я чуть с дуба не рухнул, когда узнал, что изменить запрос у них означает выключить индекс вообще :)
То есть правильный ответ, с их точки зрения, это предварительный SET LOCAL enable_indexscan = off; , что ли? Бре-е-ед..
да, бред. думаю правильно:
drop index msg_idx;
create index msg_idx on msg (process_date) where status <> '10782572'::numeric;
в запрос добавить for no key update skip locked
лучше так:
CREATE INDEX msg_unprocessed_idx ON msg (process_date, id)
WHERE status <> 10782572;-- для очередей явно задавать порядок
id в include?
вряд ли, увеличится размер индекса; более сложно; там всего 100 строк; спросят что вы знаете о BitmapAnd. Про важность unit of order при обработке сообщений в очередях можно просто упомянуть
вряд ли, увеличится размер индекса
В этом индексе лежат только необработанные строки. А вот батч-выборка ORDER BY process_date, id — стабильная.
Ну да. С таким индексом никаких дополнительных плясок в коде не нужно. Это намного больше похоже на обработку очереди. Только в задании сказано тупо поменять запрос. Ой. Индекс выключить. Ой. Бог знает что сделать с дырками после обработки.
Я на самом деле не знаю, что было правильным ответом. Вот честно. Все что они мне сказали я тут привел. Но вот про мешающий индекс точно звучало. А я со стула упал.
Угу, есть такая проблема с интервью, когда что-то не говоришь т.к. считаешь, что это очевидно всем и нет нужны проговаривать, а потом узнаешь, что тебя отсеяли т.к. ты якобы не знаешь очевидных вещей. Поэтому надо на интервью все рассуждения, что лезут в голову, учиться озвучивать не стесняясь. Первым делом увидев эту задачу сказать, что надо индекс менять, а не запрос, а потом сказать, что раз по-условию менять именно запрос, буду пытаться что-то с этим сделать, хоть и добиться результатов близких к правильному индексу будет невозможно.

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