Я оптимизирую множество существующих запросов в своем проекте. Решение Quassnoi помогло мне значительно ускорить запросы! Однако мне сложно включить указанное решение во все запросы, особенно для сложных запросов, включающих множество подзапросов в нескольких больших таблицах.
Поэтому я использую менее оптимизированное решение. По сути, это работает так же, как решение Quassnoi.
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / [accomodation_table_row_count]
LIMIT $size
$size * $factor / [accomodation_table_row_count]
определяет вероятность выбора случайной строки. Rand () сгенерирует случайное число. Строка будет выбрана, если rand () меньше или равна вероятности. Это эффективно выполняет случайный выбор для ограничения размера таблицы. Поскольку существует вероятность того, что он вернет меньше заданного предела, нам нужно увеличить вероятность, чтобы убедиться, что мы выбираем достаточно строк. Следовательно, мы умножаем $ size на $ factor (я обычно устанавливаю $ factor = 2, в большинстве случаев работает). Наконец мы делаемlimit $size
Теперь проблема заключается в том, чтобы разобраться с encodation_table_row_count . Если мы знаем размер таблицы, мы МОЖЕМ жестко закодировать размер таблицы. Это будет работать быстрее всего, но, очевидно, это не идеально. Если вы используете Myisam, подсчет таблиц очень эффективен. Поскольку я использую innodb, я просто делаю простой подсчет + выбор. В вашем случае это будет выглядеть так:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / (select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
Сложная часть - вычислить правильную вероятность. Как видите, следующий код фактически вычисляет только приблизительный размер временной таблицы (на самом деле, слишком грубый!): (select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
Но вы можете уточнить эту логику, чтобы дать более точное приближение к размеру таблицы. Обратите внимание, что лучше выбрать ПЕРЕБРАТЬ, чем выделить строки ниже. то есть, если вероятность слишком низкая, вы рискуете не выбрать достаточно строк.
Это решение работает медленнее, чем решение Quassnoi, так как нам нужно пересчитать размер таблицы. Однако я считаю, что это кодирование намного более управляемо. Это компромисс между точностью + производительностью и сложностью кодирования . При этом на больших таблицах это все еще намного быстрее, чем Order by Rand ().
Примечание. Если логика запроса позволяет, выполните случайный выбор как можно раньше перед любыми операциями соединения.