Comments 24
Если там появляется постраничная навигация, то возникает даже риск потери контактов на границах страниц.
Скажем с комментами может быть такая проблема. Если они отображаются в формате «10 последних на 1 странице», то листая до конца страницы №2 и более нужно будет обновить страницу и глянуть, не появилось ли что-то за время чтения. На примере samlib.ru.
Не совсем понял пример.
В моём примере подразумевалось, что если мы делаем пагинацию без оффсетов (при использовании которых есть свои проблемы), а на базе условий вида WHERE created < "2019-10-08 12:13:14" ORDER BY created DESC LIMIT 10
(где 2019-10-08 12:13:14 — это время последнего объекта предыдущей страницы, а 10 — количество записей на страницу), то мы не покажем другие объекты с тем же значением created
если они есть, но не попали на предыдущую страницу из-за лимита записей на эту самую страницу.
Да, все эти записи будут проигнорированы при выборке. Если же заменить условие created < X
на created <= X
, то сюда попадёт и та запись, что уже была показана на предыдущей странице.
Эту проблему тоже можно решить — добавить к сортировке и фильтру по created
второе поле, уникальное для каждой записи (тот же автоинкрементный id, например), но придётся усложнять условия выборки. Запрос на выборку страницы тогда будет выглядеть как-то так:
SELECT id, created
FROM CommentsTable
WHERE ((created > :last_shown_created) OR (created = :last_shown_created AND id > :last_shown_id))
ORDER BY created ASC, id ASC
LIMIT 10
Тут в условии (created = :last_shown_created AND id >:last_shown_id)
отвечает за корректную обработку случая, когда есть несколько записей в то же время, что и у граничной записи, а (created > :last_shown_created)
за обработку случая, когда их нет.
Честно говоря, такой запрос выглядит страшно и не думаю, что хорошо использует индексы. Если можно избегать таких условий, то я стараюсь их избегать.
Повышение точности значения времени — самый простой способ уменьшить вероятность появления записей с одним и тем же временем на границе страниц (но совсем избавиться от неё нельзя) без серьёзного изменения кода.
Есть и другие способы для решения этой проблемы, но они не имеют отношения к времени и это уже совсем другая история...
И все же. Привязка только ко времени не дает стопроцентной гарантии правильного порядка, на примере писем. Банально даже ntp клиент отработает и скорректирует время на те самые доли секунд и порядок писем уже будет неправильный. Мне кажется, что сортировка по автоинкременту вне конкуренции.
Да, вы правы — время может быть скорректировано и порядок будет неправильные на те самые доли секунды. Но этим примером я хотел проиллюстрировать пагинацию на основе значения времени. Несмотря на этот неправильный порядок, вызванный корректировкой времени, мы не потеряем записи на границах страницы (как всегда с оговоркой — при условии, что потом не появится новых с тем же временем).
Библиотека, которая подменяет собой стандартные DateTime и DateInterval (нужно только use поправить по проекту). Сейчас вряд ли пригодна к использованию, так как не обновлял ее давно, но задумался, что в нее можно вдохнуть новую жизнь.
А есть реальные задачи, где время с такой точностью нужно?
У меня были различные логи которые писались в разные таблицы и имели разный форм, типа отправка почты, изменения статуса, отсправка запроса на сторонний сервис и так далее, и все это выполнялось в одном запросе, и чтобы потом адекватно понять последовательность действий добавил микрсекунды, после этого я смог адекватно вывести лог всех действий в админ-панели, в нужном порядке.
У них был конечно свой порядок, но в связи с чем что в одном месте мы вначале меняем данные, а потом отправляем письмо, а в другом месте наоборот, мы не могли их выводить в одном списке в верной сортировке.
Можно было конечно выводить это все в разных табличках, но потом сложно прыгать по ним и пытаться соотнести, что же именно проиходило, и в какой последовательности.
Сортировка по уникальному идентификатору — это очень хорошо и если можно её использовать, то лучше сделать это. К сожалению она не всегда подходит. Вот несколько примеров, где эта сортировка не поможет:
- список статей автора на Хабре, отсортированных по времени публикации — идентификатор статьи появляется в момент создания черновика, но разные статьи-черновики могут публиковаться в разном порядке и черновик, созданный позже может быть опубликован раньше.
- список контактов в любом мессенджере, отсортированный по времени последнего сообщения — в старом контакте может появиться новое сообщение и нужно будет поднять его на самый верх.
В обоих случаях можно обойтись без дат если ввести дополнительный идентификатор, отражающий порядок сортировки (счетчик публикации для первого примера, счётчик сообщений для второго), но при его использовании есть свои проблемы: как минимум нужно гарантировать его уникальность, а использовать автоинкремент уже не получится. Я не уверен, что это будет проще, чем использовать время публикации/обновления.
В своём первом комментарии вы говорите про две вещи:
- сортировки по времени не нужны, а нужны по ID
- непонятно, зачем нужна такая точность времени.
Я привёл примеры против первого тезиса, но не успел ничего написать про второй пункт. Т.е. да, в этих примерах высокая точность может быть не нужна, а вот сортировка по дате очень даже.
Более того, мессенджер как-то свои сообщения локально хранит и их айдишники наверняка на время тоже завязаны.
Я говорю не про сообщения, а про контакты (главную страницу любого мессенджера). Там записи обновляются много раз (при получении нового сообщения), а создаются (и получают идентификатор) только один раз.
А есть реальные задачи, где время с такой точностью нужно?
Вам уже писали про лог. У нас есть подобный лог операций над фотографиями. Микросекундная точность там помогает в восстановлении порядка выполнения операций, которые выполняются в разных частях системы и это помогает разбираться с "подземными стуками", когда возникают баги, которые не получается воспроизвести.
Другой пример — замер времени доставки сообщений чата между базами данных отправителя и получателя. Это физически разные базы и хочется понимать, сколько времени происходит между отправкой сообщений (записью её в базу отправителя) и доставкой (базу получателя). При секундной точности разницу между 0.05 и 0.95 секунды будет не видна, а при повышении точности времени в базе — вполне.
Главная вещь, к которой я призываю — не использовать на автомате время с секундной точностью (потому что "её хватит всем"). Вместо этого стоит задумываться о том, не будет ли пользы от большей точности и если будет, то инструменты для работы с ней уже есть и их можно использовать. Если вам достаточно порядка, то в этом нет ничего плохого, не нужно использовать максимальную точность времени.
Немного пугает о том что в блоге Badoo пишут о Yii.
Я хотел проиллюстрировать, как работают миграции с временем высокой точности. Изначально план был сделать несколько примеров для разных фреймворков, но в процессе я решил что достаточно будет и одного примера. В результате в статью попал тот, что был сделан первым (с Yii у меня лично самый большой практический опыт среди популярных фреймворков, поэтому начал именно с него).
Насколько мне известно, в кодовой базе Badoo нет Yii (но есть немного Laravel и Symfony Components).
Время высокой точности: как работать с долями секунды в MySQL и PHP