Во второй части мы заменили запрос к базе с сортировкой на сортировку в PHP — так кэш запросов перестал мешать. Такая замена безопасна, только если порядок однозначен. Если у двух товаров одинаковое значение поля сортировки, их взаимный порядок выбирает база, и повторить его в PHP нельзя. На тесте таких пар не было ни одной. На рабочем сайте их было три.

Это третья часть цикла «Массовый импорт в WordPress».

Откуда ничьи

Порядок товаров задаёт поле order, его присылает учётная система. Значения ставят люди, и совпадения неизбежны: два трактора с order = 225. Запрос orderby => meta_value_num отсортирует их рядом, но кто из двух первый — решает база, а не мы.

Тест и рабочий сайт расходятся именно здесь: на тестовой копии совпадений не оказалось ни одного. Проверка «на тесте всё совпало» ничего не говорит о ничьих — их надо искать запросом на рабочих данных.

SELECT meta_value, COUNT(*) AS n, GROUP_CONCAT(post_id) AS ids
FROM wp_postmeta pm JOIN wp_posts p ON p.ID = pm.post_id
WHERE pm.meta_key = 'order' AND p.post_type = 'katalog' AND p.post_status = 'publish'
GROUP BY meta_value HAVING n > 1;

Первое решение: при ничьей — по-старому

На первом сайте сделали осторожно: функция, строящая таблицу порядка, возвращает null, если в наборе есть ничья, и код идёт прежним медленным путём через get_posts. Ничьих было три пары на весь каталог, медленный путь срабатывал редко.

Когда ту же правку переносили на второй сайт, это решение обесценило всю работу. Там пара с одинаковым order попадала в каждое крупное объединение товаров: из 10 самых связных товаров все 10 шли по медленному пути.

Самый связный товарВремя записи
без ничьей в наборе2,15 с
с ничьей — запасной путь16,83 с

Прежнего поведения не существует

Запасной путь строился на желании «сохранить, как было». Проверка показала, что сохранять нечего. База возвращает равные значения в разном порядке в зависимости от набора include: у одного товара 12 адресатов из 101 получали эту пару в другом порядке, чем остальные. Один и тот же товар в разных списках стоял то выше, то ниже соседа.

Решение — сделать порядок однозначным вторым ключом сортировки:

'orderby' => ['meta_value_num' => 'ASC', 'ID' => 'ASC'],

И в PHP — то же правило: при равном order меньший ID идёт первым. Теперь база и PHP дают одинаковый порядок всегда, запасной путь не нужен. Если людям не понравится, какой из двух товаров первый, — это решается в учётной системе: проставить разные значения order.

Проверить, что ничья вообще на что-то влияет

На втором сайте нашлось четыре группы с одинаковым order, но три из них оказались безобидными: навесное оборудование, у которого списки совместимости хранятся на нём самом и содержат тракторы. На порядок внутри групп такие ничьи не влияли вовсе. Решающий вопрос не «есть ли ничья», а «попадает ли она в список, который мы строим».

Ещё одно отличие сайтов: данные, а не способ

У двух сайтов с общей родословной темы оказалась разная структура меты: на одном список хранится отсортированным и без общего названия, на другом — в исходном порядке и с ним. Ускорять надо способ получения данных, а что именно записывается, оставлять как было в проекте. Перенос «как на первом сайте» поменял бы данные на втором.

Переносите оптимизацию с одного сайта на другой?

Пришлите оба — сверю данные и найду места, где «одинаковый» код ведёт себя по-разному.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.