Разбивка на страницы и как вернуть все возможные варианты вместе с результатами поиска в базе данных? - PullRequest
0 голосов
/ 15 марта 2020

Я работаю над базой данных, содержащей более 5 миллионов строк.

Вопрос 1.

В данный момент я делаю следующее:

SELECT COUNT(*) FROM cars

Количество строк, которые должны быть возвращены. Приведенный выше пример очень простой c. Запросы усложняются с предложением WHERE.

Я показываю 50 строк на странице. Используя PHP, я считаю общее количество страниц и смещение на основе текущей страницы, полученной из PHP $ _GET. Это передается следующему запросу:

SELECT ID FROM cars ORDER BY ID DESC LIMIT $offset, 50

Я выбираю все идентификаторы строк, которые должны отображаться на текущей странице, помещаю их в одну строку.

$ID_list = implode( ',', array_column( $mysqli_fetch, 'ID' ) );

Затем передается окончательный запрос.

SELECT ID, make, model, year, price FROM cars WHERE ID IN ($ID_list)

По производительности я считаю, что передача идентификаторов в третий запрос выполняется в 8 раз быстрее, чем просто выбор всех необходимых столбцов во втором запросе.

Какой самый эффективный способ разбивать результаты на страницы при отображении общего количества строк и номеров страниц. В то время как ОГРАНИЧЕНИЕ, разбиение на страницы LIMIT неэффективно, использование метода поиска не позволяет отобразить номера страниц. Есть ли альтернативный метод? Может быть, мне стоит заняться технологиями, отличными от MySQLi?

Вопрос 2.

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

https://www.autotrader.co.uk/car-search?advertClassification=standard&postcode=B4%206TB&onesearchad=Used&onesearchad=Nearly%20New&onesearchad=New&advertising-location=at_cars&is-quick-search=TRUE&page=1

Поиск на вышеуказанном веб-сайте начинается без применения фильтров. Теперь я могу нажать, например, «Сделать», и рядом с маркой автомобиля отображается ряд возможных результатов. То же самое касается любого другого варианта. Как это достигается?

1 Ответ

0 голосов
/ 15 марта 2020

Проблемы и их решение в вопросе 1 обсуждаются в http://mysql.rjweb.org/doc.php/pagination

, в котором настоятельно рекомендуется «запомнить, где вы остановились» вместо OFFSET, что обеспечивает значительное улучшение производительности. Он избавляется от $ID_list и позволяет вам сделать два SELECTs как один (что является еще одним преимуществом в производительности). (Ваше 8-кратное улучшение произошло из-за комбинации выбора нескольких столбцов и пропуска строк (OFFSET).)

Вопрос 2 сложнее, так как вы хотите сделать несколько подсчетов. Попробуйте использовать GROUP BY и COUNT(*), чтобы получить все значения в одном запросе. Риск состоит в том, что для этого может потребоваться столько данных (например, всех строк 5М), что это займет «слишком много времени». В тех немногих случаях, когда доступен «покрывающий» индекс, он не может быть «слишком длинным».

Вы могли бы делать большие групповые переходы каждую ночь - подсчитывает по марке и нет фильтрация, рассчитывается по модельному году и без фильтрации и т. д. c. Храните их в таблице для быстрой загрузки. Как только вы добавляете фильтрацию, сложность делает это непрактичным. Примечание: выполнение такого ночного подсчета подразумевает, что вы анализируете запрос пользователя, чтобы адаптировать SELECT.

Даже счетчик-сколько-сколько-ряд-мы-о-на-страницу-через (вопроса 1) может быть слишком дорогостоящим.

См. здесь, как отделить «общие» атрибуты от «редких»: http://mysql.rjweb.org/doc.php/eav. Это приводит к нескольким составным запросам из 2-3 столбцов для обработки большинства из SELECT от людей со случайными критериями фильтрации.

Уменьшите размер таблицы, используя минимальные типы данных , Model_year может использовать 2-байтовый тип данных YEAR. Auto_in c для автомобилей 5M может использовать 3-байтовый MEDIUMINT UNSIGNED (предел 16M).

Нормализация (замена длинной строки коротким идентификатором) экономит место, но, вероятно, будет стоить слишком дорого, если запросы фильтруются по нескольким критериям. Например: make = 'Ford' AND model = 'F150'.

AND относительно легко оптимизировать в предложении WHERE; IN хуже, а OR еще хуже. В некоторых случаях IN и OR вам, возможно, придется прибегнуть к UNION, чтобы избавиться от них. Пример:

( SELECT ... WHERE make = 'BMW' )
UNION ALL
( SELECT ... WHERE make = 'Audi' )

В ряде других случаев вам действительно нужно «построить» запрос в коде приложения, а не просто надеяться, что MySQL сможет сделать что-то оптимальное.

Выше UNION не допускает нумерацию страниц; см. мои ссылки о том, как бороться с такими.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...