Я оптимізую багато існуючих запитів у своєму проекті. Рішення 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
Зараз проблема полягає в розробці accomodation_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))
Але ви можете уточнити цю логіку, щоб наблизити приблизне розмір таблиці. Зверніть увагу, що краще НАД-вибрати, ніж недобирати рядки. тобто якщо ймовірність встановлена занадто низькою, ви ризикуєте не виділити достатню кількість рядків.
Це рішення працює повільніше, ніж рішення Квасноя, оскільки нам потрібно перерахувати розмір таблиці. Однак я вважаю це кодування набагато більш керованим. Це компроміс між точністю + продуктивністю та складністю кодування . Сказавши це, на великих столах це все ще набагато швидше, ніж Order by Rand ().
Примітка: Якщо логіка запиту дозволяє, виконайте випадковий вибір якомога раніше перед будь-якими операціями приєднання.