Pull to refresh

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 если они есть, но не попали на предыдущую страницу из-за лимита записей на эту самую страницу.

Может пропасть несколько записей с временем создания 12:13:14<t<12:13:14.999, если последняя запись предыдущей страницы попала в этот диапазон (и время создания было конвертировано в 12:13:14)?

Да, все эти записи будут проигнорированы при выборке. Если же заменить условие 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 клиент отработает и скорректирует время на те самые доли секунд и порядок писем уже будет неправильный. Мне кажется, что сортировка по автоинкременту вне конкуренции.

Да, вы правы — время может быть скорректировано и порядок будет неправильные на те самые доли секунды. Но этим примером я хотел проиллюстрировать пагинацию на основе значения времени. Несмотря на этот неправильный порядок, вызванный корректировкой времени, мы не потеряем записи на границах страницы (как всегда с оговоркой — при условии, что потом не появится новых с тем же временем).

Очень интересная заметка. Выражаю благодарность. Как-то я прошляпил, что в 7 версии добавили миллисекунды. Еще в эру PHP 5.4+ у нас в проекте возникла потребность в миллисекундах, в итоге на свет родилось такое вот творение для работы с микросекундами (округлить вниз до миллисекунд — плевое дело) — github.com/Alroniks/dtms
Библиотека, которая подменяет собой стандартные DateTime и DateInterval (нужно только use поправить по проекту). Сейчас вряд ли пригодна к использованию, так как не обновлял ее давно, но задумался, что в нее можно вдохнуть новую жизнь.

Интересно. Кажется, что с помощью такой обёртки можно править баги при работе с временем, если обновить версию PHP нельзя или попался новый еще неисправленный баг.

Не понял, как связаны временные метки с проблемными ситуациями. Везде сортировка и выборка должна осуществляться по ID записи, но никак не по времени. Это и дольше и по смыслу не особо нужно. Если нужна фильтрация во временном диапазоне у сущностей с фиксированными ID, то проблемная ситуация возможна, хотя опять же метки временные скорее всего не пригодятся.

А есть реальные задачи, где время с такой точностью нужно?

У меня были различные логи которые писались в разные таблицы и имели разный форм, типа отправка почты, изменения статуса, отсправка запроса на сторонний сервис и так далее, и все это выполнялось в одном запросе, и чтобы потом адекватно понять последовательность действий добавил микрсекунды, после этого я смог адекватно вывести лог всех действий в админ-панели, в нужном порядке.

Так у них порядок свой внутренний в запросе был или они в случайном порядке это делали? Какой смысл их смешивать, если они действительно разные?

У них был конечно свой порядок, но в связи с чем что в одном месте мы вначале меняем данные, а потом отправляем письмо, а в другом месте наоборот, мы не могли их выводить в одном списке в верной сортировке.
Можно было конечно выводить это все в разных табличках, но потом сложно прыгать по ним и пытаться соотнести, что же именно проиходило, и в какой последовательности.

Сортировка по уникальному идентификатору — это очень хорошо и если можно её использовать, то лучше сделать это. К сожалению она не всегда подходит. Вот несколько примеров, где эта сортировка не поможет:


  1. список статей автора на Хабре, отсортированных по времени публикации — идентификатор статьи появляется в момент создания черновика, но разные статьи-черновики могут публиковаться в разном порядке и черновик, созданный позже может быть опубликован раньше.
  2. список контактов в любом мессенджере, отсортированный по времени последнего сообщения — в старом контакте может появиться новое сообщение и нужно будет поднять его на самый верх.

В обоих случаях можно обойтись без дат если ввести дополнительный идентификатор, отражающий порядок сортировки (счетчик публикации для первого примера, счётчик сообщений для второго), но при его использовании есть свои проблемы: как минимум нужно гарантировать его уникальность, а использовать автоинкремент уже не получится. Я не уверен, что это будет проще, чем использовать время публикации/обновления.

Но в этих ситуациях повышенная точность времени не нужна, даже разбежки в несколько секунд простительны. Более того, мессенджер как-то свои сообщения локально хранит и их айдишники наверняка на время тоже завязаны.

В своём первом комментарии вы говорите про две вещи:


  1. сортировки по времени не нужны, а нужны по ID
  2. непонятно, зачем нужна такая точность времени.

Я привёл примеры против первого тезиса, но не успел ничего написать про второй пункт. Т.е. да, в этих примерах высокая точность может быть не нужна, а вот сортировка по дате очень даже.


Более того, мессенджер как-то свои сообщения локально хранит и их айдишники наверняка на время тоже завязаны.

Я говорю не про сообщения, а про контакты (главную страницу любого мессенджера). Там записи обновляются много раз (при получении нового сообщения), а создаются (и получают идентификатор) только один раз.

В отрыве от точности я могу и сам придумать десятки примеров, где что-то можно сортировать по времени. Тут же на время с точностью до дробных секунд опираются как на основную характеристику выборки, потому я её имею в виду как само обязательное условие.
А есть реальные задачи, где время с такой точностью нужно?

Вам уже писали про лог. У нас есть подобный лог операций над фотографиями. Микросекундная точность там помогает в восстановлении порядка выполнения операций, которые выполняются в разных частях системы и это помогает разбираться с "подземными стуками", когда возникают баги, которые не получается воспроизвести.


Другой пример — замер времени доставки сообщений чата между базами данных отправителя и получателя. Это физически разные базы и хочется понимать, сколько времени происходит между отправкой сообщений (записью её в базу отправителя) и доставкой (базу получателя). При секундной точности разницу между 0.05 и 0.95 секунды будет не видна, а при повышении точности времени в базе — вполне.

Вот такие вещи уже интереснее. Но тут уже возникает вопрос о пользе такой точности исходя из этого. И в том и в другом случае важен именно порядок действий, а не время. За порядок всё же должен отвечать порядковый номер, некий «ID», а временное расстояние между элементами системы скорее всего нет нужды выяснять более чем один-два раза. Если операций выполняется много и в разных местах, логично замерять по ним какие-то обобщённые величины, время выполнения некого пакета действий, но не каждое с безумной точностью.

Главная вещь, к которой я призываю — не использовать на автомате время с секундной точностью (потому что "её хватит всем"). Вместо этого стоит задумываться о том, не будет ли пользы от большей точности и если будет, то инструменты для работы с ней уже есть и их можно использовать. Если вам достаточно порядка, то в этом нет ничего плохого, не нужно использовать максимальную точность времени.

Не понял, как связаны временные метки с проблемными ситуациями. Везде сортировка и выборка должна осуществляться по ID записи, но никак не по времени. Это и дольше и по смыслу не особо нужно.

А есть реальные задачи, где время с такой точностью нужно?

Жизненная ситуация — gps-терминалы для мониторинга передвижения. При отсутствии связи данные хранятся в памяти и передаются при восстановлении связи. Все бы хорошо, но многие модели передают накопленные данные в хаотичном порядке. А выводить надо по-порядку, по времени.

Так же многие модели могут выдавать несколько пакетов в секунду, а значит и такая точность нужна.
Так а ID своим записям они не проставляют? На время ориентироваться зачем?
Нет, там масса своих нюансов с сотнями разных терминалов от разных производителей.

Немного пугает о том что в блоге Badoo пишут о Yii.

Я хотел проиллюстрировать, как работают миграции с временем высокой точности. Изначально план был сделать несколько примеров для разных фреймворков, но в процессе я решил что достаточно будет и одного примера. В результате в статью попал тот, что был сделан первым (с Yii у меня лично самый большой практический опыт среди популярных фреймворков, поэтому начал именно с него).


Насколько мне известно, в кодовой базе Badoo нет Yii (но есть немного Laravel и Symfony Components).

Only those users with full accounts are able to leave comments. Log in, please.