Відповіді:
Чудовий пост, що обробляє декілька випадків, від простих, до прогалин, до нерівномірних з прогалинами.
http://jan.kneschke.de/projects/mysql/order-by-rand/
У більшості випадків, ось як це зробити:
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
Це передбачає, що розподіл ідентифікаторів рівний, і що у списку id можуть бути прогалини. Докладніші приклади див. У статті
mysqli_fetch_assoc($result)
? Або ці 10 результатів не обов'язково відрізняються?
SELECT column FROM table
ORDER BY RAND()
LIMIT 10
Не ефективне рішення, але працює
ORDER BY RAND()
відносно повільний
SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10
займає 0,0010, без обмеження 10 знадобився 0,0012 (у цій таблиці 3500 слів).
Простий запит, який має відмінні показники та працює з прогалинами :
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) as t2 ON t1.id=t2.id
Цей запит на таблиці 200K займає 0,08 секунди, а звичайна версія (ВИБІР * З ТБ ЗАМОВЛЕННЯ ПО РАНДУ () ГРОМИ 10) займає 0,35 секунди на моїй машині.
Це швидко, тому що фаза сортування використовує лише індексований стовпчик ідентифікатора. Ви можете бачити таку поведінку в поясненні:
ВИБІР * З ТБ ЗАМОВЛЕННЯ ПО ГРАНІ 10)
ВИБІР * ВІД tbl AS t1 ПРИЄДНАЙТЕСЬ (ВИБІР ІД ІЗ tbl ЗАМОВЛЕННЯ ПО ГРАНІ () ГРОМ 10) як t2 НА t1.id = t2.id
Зважена версія : https://stackoverflow.com/a/41577458/893432
Я отримую швидкі запити (приблизно 0,5 секунди) з повільним процесором , вибираючи 10 випадкових рядків у 400 К реєструє базу даних MySQL, не кешований розміром 2 Гб. Дивіться тут мій код: Швидкий вибір випадкових рядків у MySQL
<?php
$time= microtime_float();
$sql='SELECT COUNT(*) FROM pages';
$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);
$sql="SELECT id FROM pages WHERE RAND()*$num_records<20
ORDER BY RAND() LIMIT 0,10";
$rquery= BD_Ejecutar($sql);
while(list($id)=mysql_fetch_row($rquery)){
if($id_in) $id_in.=",$id";
else $id_in="$id";
}
mysql_free_result($rquery);
$sql="SELECT id,url FROM pages WHERE id IN($id_in)";
$rquery= BD_Ejecutar($sql);
while(list($id,$url)=mysql_fetch_row($rquery)){
logger("$id, $url",1);
}
mysql_free_result($rquery);
$time= microtime_float()-$time;
logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);
?>
ORDER BY RAND()
FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';
щоб побачити це.
ORDER BY RAND()
полягає в тому, що він сортує лише ідентифікатори (не повні рядки), тому таблиця тимчасових розмірів менша, але все одно має сортувати їх.
Його дуже простий і однорядний запит.
SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
order by rand()
дуже повільно, якщо стіл великий
З книги:
Виберіть випадковий рядок за допомогою зміщення
Ще одна методика, яка дозволяє уникнути проблем, знайдених у попередніх альтернативах, - це підрахунок рядків у наборі даних та повернення випадкового числа між 0 та підрахунком. Потім використовуйте це число як компенсацію при запиті набору даних
<?php
$rand = "SELECT ROUND(RAND() * (SELECT COUNT(*) FROM Bugs))";
$offset = $pdo->query($rand)->fetch(PDO::FETCH_ASSOC);
$sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->execute( $offset );
$rand_bug = $stmt->fetch();
Використовуйте це рішення, коли ви не можете приймати суміжні значення ключів і вам потрібно переконатися, що кожен рядок має рівний шанс бути вибраним.
SELECT count(*)
стає повільним.
Як вибрати випадкові рядки з таблиці:
Звідси: Виберіть випадкові рядки в MySQL
Швидке вдосконалення щодо "сканування таблиці" полягає у використанні індексу для підбору випадкових ідентифікаторів.
SELECT *
FROM random, (
SELECT id AS sid
FROM random
ORDER BY RAND( )
LIMIT 10
) tmp
WHERE random.id = tmp.sid;
PRIMARY KEY
).
Добре, якщо у вас немає прогалин у ваших клавішах, і всі вони є числовими, ви можете обчислити випадкові числа і вибрати ці рядки. але це, мабуть, не так.
Таким рішенням було б таке:
SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1
що в основному забезпечить отримання випадкового числа в діапазоні ваших ключів, а потім ви виберете наступне найкраще, яке більше. ви повинні зробити це 10 разів.
однак це НЕ насправді випадково, оскільки ваші ключі, швидше за все, не будуть розподілятися рівномірно.
Це справді велика проблема, і вирішити всі вимоги непросто, rand MySQL () - найкраще, що ви можете отримати, якщо ви дійсно хочете 10 випадкових рядків.
Однак є ще одне рішення, яке швидко, але також має змогу торгуватись випадковістю, але може підходити вам краще. Про це читайте тут: Як я можу оптимізувати функцію ORDER BY RAND () MySQL?
Питання в тому, наскільки випадковим воно вам потрібно.
Чи можете ви пояснити трохи більше, щоб я міг дати вам хороше рішення.
Наприклад, у компанії, з якою я працював, було рішення, де вони дуже швидко потребували абсолютної випадковості. Вони закінчилися попереднім заповненням бази даних випадковими значеннями, які були вибрані у спадному порядку і знову встановлені на різні випадкові значення.
Якщо ви навряд чи коли-небудь оновлюєтесь, ви також можете заповнити приріст ідентифікатора, щоб у вас не було прогалин, і ви можете просто обчислити випадкові ключі перед вибором ... Це залежить від випадку використання!
Id
і всі ваші випадкові запити повернуть вам цей Id
.
FLOOR(RAND()*MAX(id))
схильний до повернення більших ідентифікаторів.
Мені потрібен запит, щоб повернути велику кількість випадкових рядків із досить великої таблиці. Це те, що я придумав. Спочатку отримайте максимальний ідентифікатор запису:
SELECT MAX(id) FROM table_name;
Потім замініть це значення на:
SELECT * FROM table_name WHERE id > FLOOR(RAND() * max) LIMIT n;
Де max - максимальний ідентифікатор запису в таблиці, а n - кількість рядків, які потрібно отримати в наборі результатів. Припущення полягає в тому, що в ідентифікаторах записів немає прогалин, хоча я сумніваюся, що це вплине на результат, якщо вони були (хоч би не пробували). Я також створив цю збережену процедуру, щоб бути більш загальною; введіть назву таблиці та кількість рядків, які потрібно повернути. Я запускаю MySQL 5.5.38 на Windows 2008, 32 Гб, подвійний 3 ГГц E5450, а на таблиці з 17 311 264 рядками це досить послідовно за ~ 0,03 сек / ~ 11 сек, щоб повернути 1 000 000 рядків. (час від MySQL Workbench 6.1; ви також можете використовувати CEIL замість FLOOR у другому операторі select, залежно від ваших уподобань)
DELIMITER $$
USE [schema name] $$
DROP PROCEDURE IF EXISTS `random_rows` $$
CREATE PROCEDURE `random_rows`(IN tab_name VARCHAR(64), IN num_rows INT)
BEGIN
SET @t = CONCAT('SET @max=(SELECT MAX(id) FROM ',tab_name,')');
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @t = CONCAT(
'SELECT * FROM ',
tab_name,
' WHERE id>FLOOR(RAND()*@max) LIMIT ',
num_rows);
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$
тоді
CALL [schema name].random_rows([table name], n);
Я покращив відповідь @Riedsio. Це найефективніший запит, який я можу знайти на великій, рівномірно розподіленій таблиці з пробілами (тестується на отримання 1000 випадкових рядків із таблиці, що має> 2,6B рядків).
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
Дозвольте розпакувати, що відбувається.
@max := (SELECT MAX(id) FROM table)
MAX(id)
кожного разу, коли вам потрібен рядSELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
Здійснення спілки допомагає вам укласти все в 1 запит, щоб уникнути виконання декількох запитів. Це також дозволяє заощадити накладні обчисленняMAX(id)
. Залежно від вашої заявки, це може мати значення чи дуже мало.
Зауважте, що це отримує лише ідентифікатори та отримує їх у випадковому порядку. Якщо ви хочете зробити щось більш досконале, рекомендую зробити це:
SELECT t.id, t.name -- etc, etc
FROM table t
INNER JOIN (
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
) x ON x.id = t.id
ORDER BY t.id
LIMIT 1
на LIMIT 30
запит скрізь
LIMIT 1
до LIMIT 30
отримаєте вас 30 записів поспіль від випадкової точки в таблиці. Натомість у вас має бути 30 копій (SELECT id FROM ....
деталі посередині.
Riedsio
відповісти. Я намагався з 500 за секунду звернень до сторінки, використовуючи PHP 7.0.22 та MariaDB на centos 7, з Riedsio
відповіддю я отримав 500+ додаткових успішних відповідей, а потім вашу відповідь.
Я використав цей http://jan.kneschke.de/projects/mysql/order-by-rand/, опублікований Рієдсіо (я використовував випадок збереженої процедури, яка повертає одне або більше випадкових значень):
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
INSERT INTO rands
SELECT r1.id
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
У статті він вирішує проблему прогалин у ідентифікаторах, що спричиняють не такі випадкові результати , підтримуючи таблицю (використовуючи тригери тощо). Я вирішую проблему, додавши ще один стовпець до таблиці, заповненої суміжними номерами, починаючи з 1 ( редагувати: цей стовпець додається до тимчасової таблиці, створеної підзапитом під час виконання, не впливає на вашу постійну таблицю):
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
SET @no_gaps_id := 0;
INSERT INTO rands
SELECT r1.id
FROM (SELECT id, @no_gaps_id := @no_gaps_id + 1 AS no_gaps_id FROM random) AS r1 JOIN
(SELECT (RAND() *
(SELECT COUNT(*)
FROM random)) AS id)
AS r2
WHERE r1.no_gaps_id >= r2.id
ORDER BY r1.no_gaps_id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
У статті я можу побачити, що він намагався оптимізувати код; у мене немає ідеї, якщо / наскільки мої зміни впливають на продуктивність, але дуже добре працюють на мене.
@no_gaps_id
індексу не може бути використаний, так що якщо ви подивіться на EXPLAIN
ваш запит, у вас є Using filesort
і Using where
(без індексу) для підзапитів, на відміну від початкового запиту.
Ось мінялка гри, яка може бути корисною для багатьох;
У мене є таблиця з 200k рядками, з послідовними ідентифікаторами , мені потрібно було вибрати N випадкових рядків, тому я вирішу генерувати випадкові значення на основі найбільшого ідентифікатора в таблиці, я створив цей скрипт, щоб дізнатися, яка найшвидша операція:
logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();
Результати:
36.8418693542479
мс0.241041183472
мс0.216960906982
мсВиходячи з цих результатів, опис замовлення - це найшвидша операція, щоб отримати максимальний ідентифікатор,
Ось моя відповідь на питання:
SELECT GROUP_CONCAT(n SEPARATOR ',') g FROM (
SELECT FLOOR(RAND() * (
SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 10) a
...
SELECT * FROM tbl WHERE id IN ($result);
FYI: Щоб отримати 10 випадкових рядків з таблиці 200k, мені знадобилося 1,78 мс (включаючи всі операції на стороні php)
LIMIT
трохи збільшити - ви можете отримати дублікати.
Усі найкращі відповіді вже розміщені (в основному ті, що посилаються на посилання http://jan.kneschke.de/projects/mysql/order-by-rand/ ).
Хочу визначити ще одну можливість прискорення - кешування . Подумайте, чому вам потрібно отримати випадкові рядки. Можливо, ви хочете відобразити якусь випадкову публікацію чи випадкову рекламу на веб-сайті. Якщо ви отримуєте 100 запитів / с, чи справді потрібно, щоб кожен відвідувач отримував випадкові рядки? Зазвичай ці цілком чудово кешують ці X випадкові рядки протягом 1 секунди (або навіть 10 секунд). Не має значення, якщо 100 унікальних відвідувачів за одну секунду отримують однакові випадкові повідомлення, оскільки наступної секунди ще 100 відвідувачів отримають різний набір публікацій.
При використанні цього кешування ви можете також використовувати деякі більш повільні рішення для отримання випадкових даних, оскільки вони будуть виведені з MySQL лише один раз в секунду, незалежно від ваших запитів / с.
Це дуже швидко і є 100% випадковим, навіть якщо у вас є прогалини.
x
наявних рядківSELECT COUNT(*) as rows FROM TABLE
a_1,a_2,...,a_10
між 0 іx
SELECT * FROM TABLE LIMIT 1 offset a_i
для i = 1, ..., 10Я знайшов цей злом у книзі SQL Antipatterns від Білла Карвіна .
SELECT column FROM table ORDER BY RAND() LIMIT 10
знаходиться в O (nlog (n)). Так так, це швидке рішення, і воно працює для будь-якого розповсюдження ідентифікаторів.
x
. Я б заперечив, що це не випадкове покоління з 10 рядів. У моїй відповіді, ви повинні виконати запит на етапі три 10 разів, тобто один отримує лише один рядок за виконання і не потрібно хвилюватися, якщо зміщення знаходиться в кінці таблиці.
Поєднайте відповідь @redsio з тимчасовою таблицею (600K - це не так багато):
DROP TEMPORARY TABLE IF EXISTS tmp_randorder;
CREATE TABLE tmp_randorder (id int(11) not null auto_increment primary key, data_id int(11));
INSERT INTO tmp_randorder (data_id) select id from datatable;
А потім візьміть версію @redsios Answer:
SELECT dt.*
FROM
(SELECT (RAND() *
(SELECT MAX(id)
FROM tmp_randorder)) AS id)
AS rnd
INNER JOIN tmp_randorder rndo on rndo.id between rnd.id - 10 and rnd.id + 10
INNER JOIN datatable AS dt on dt.id = rndo.data_id
ORDER BY abs(rndo.id - rnd.id)
LIMIT 1;
Якщо стіл великий, можна просіювати першу частину:
INSERT INTO tmp_randorder (data_id) select id from datatable where rand() < 0.01;
Версія: Ви можете зберігати таблицю tmp_randorder
стійкою, називати її datatable_idlist. Відтворіть цю таблицю через певні проміжки часу (день, година), оскільки вона також отримає дірки. Якщо ваш стіл стає дійсно великим, ви також можете заправити отвори
виберіть l.data_id в цілому з datatable_idlist l зліва приєднати дані dt на dt.id = l.data_id, де dt.id недійсний;
Версія: Наведіть свій набір даних у стовпчик random_sortorder або безпосередньо в даних, або в стійкій додатковій таблиці datatable_sortorder
. Індексуйте цей стовпець. Створіть у своїй програмі випадкову цінність (я її зателефоную $rand
).
select l.*
from datatable l
order by abs(random_sortorder - $rand) desc
limit 1;
Це рішення розмежовує "крайові ряди" з найвищим і найнижчим випадковим_порядком, тому переставляйте їх з інтервалом (раз на день).
Іншим простим рішенням буде класифікація рядків та отримання одного з них випадковим чином, і з цим рішенням вам не потрібно мати стовпця, що базується на "Id".
SELECT d.* FROM (
SELECT t.*, @rownum := @rownum + 1 AS rank
FROM mytable AS t,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM mytable))) AS n
) d WHERE rank >= @cnt LIMIT 10;
Ви можете змінити граничне значення відповідно до вашої потреби, щоб отримати доступ до стільки рядків, скільки вам потрібно, але це, в основному, значення послідовне.
Однак, якщо ви не хочете послідовних випадкових значень, тоді ви можете отримати більшу вибірку і вибрати її випадковим чином. щось на зразок ...
SELECT * FROM (
SELECT d.* FROM (
SELECT c.*, @rownum := @rownum + 1 AS rank
FROM buildbrain.`commits` AS c,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM buildbrain.`commits`))) AS rnd
) d
WHERE rank >= @cnt LIMIT 10000
) t ORDER BY RAND() LIMIT 10;
Один із способів, який я вважаю досить гарним, якщо є автогенерований ідентифікатор, - це використовувати модуль-оператор "%". Наприклад, якщо вам потрібно 10 000 випадкових записів із 70 000, ви можете спростити це, сказавши, що вам потрібно 1 з кожні 7 рядків. Це можна спростити в цьому запиті:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0;
Якщо результат ділення цільових рядків на загальнодоступне число не є цілим числом, у вас з’являться додаткові рядки, ніж те, про що ви просили, тому вам слід додати пункт LIMIT, щоб допомогти вам обрізати такий набір результатів:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0
LIMIT 10000;
Для цього потрібне повне сканування, але це швидше, ніж ЗАМОВЛЕННЯ РАНДОМ, і, на мій погляд, простіше зрозуміти, ніж інші варіанти, згадані в цій темі. Також якщо система, яка записує в БД, створює набори рядків у партіях, можливо, ви не отримаєте такого випадкового результату, як ви, де очікуєте.
Якщо ви хочете отримати один випадковий запис (незалежно від того, чи є проміжки між ідентифікаторами):
PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
FLOOR(RAND() * COUNT(*))
FROM `table_name`);
EXECUTE stmt USING @count;
Я переглянув усі відповіді, і не думаю, що хтось взагалі згадує про таку можливість, і не знаю, чому.
Якщо ви бажаєте максимальної простоти та швидкості, з меншими витратами, то мені здається, має сенс зберігати випадкове число проти кожного рядка в БД. Просто створіть додатковий стовпець random_number
, і встановіть його за замовчуванням RAND()
. Створіть індекс у цьому стовпці.
Потім, коли ви хочете отримати рядок, генеруйте випадковий номер у вашому коді (PHP, Perl, будь-який інший) та порівняйте його зі стовпцем.
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
Я думаю, хоча для одного ряду це дуже акуратно, на десять рядів, як ОП, попросив назвати це десять окремих разів (або придумати розумний твіст, який уникне мені негайно)
Далі слід бути швидким, неупередженим та незалежним від стовпця id. Однак це не гарантує, що кількість повернутих рядків буде відповідати кількості запитуваних рядків.
SELECT *
FROM t
WHERE RAND() < (SELECT 10 / COUNT(*) FROM t)
Пояснення: якщо припустити, що ви хочете 10 рядків із 100, то кожен рядок має 1/10 ймовірність отримати SELECTed, що може бути досягнуто WHERE RAND() < 0.1
. Такий підхід не гарантує 10 рядів; але якщо запит буде виконано достатньо разів, середня кількість рядків за виконання буде приблизно 10, і кожен рядок у таблиці буде обраний рівномірно.
PREPARE stm from 'select * from table limit 10 offset ?';
SET @total = (select count(*) from table);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
Ви також можете застосувати пункт, де так
PREPARE stm from 'select * from table where available=true limit 10 offset ?';
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
Тестоване виконання запитів таблиці на 600 000 рядків (700 МБ) займало ~ 0,016сек. HDD-диск
--EDIT--
Зсув може приймати значення, близьке до кінця таблиці, що призведе до того, що оператор select поверне менше рядків (а може бути лише 1 рядок), щоб уникнути цього, ми можемо перевірити offset
ще раз після оголошення, як це
SET @rows_count = 10;
PREPARE stm from "select * from table where available=true limit ? offset ?";
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
SET @_offset = (SELECT IF(@total-@_offset<@rows_count,@_offset-@rows_count,@_offset));
SET @_offset = (SELECT IF(@_offset<0,0,@_offset));
EXECUTE stm using @rows_count,@_offset;
Я використовую цей запит:
select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10
час запиту: 0.016s
Ось як я це роблю:
select *
from table_with_600k_rows
where rand() < 10/600000
limit 10
Мені це подобається, тому що не потрібні інші таблиці, писати просто, і це дуже швидко виконати.
Скористайтесь наведеним нижче простим запитом, щоб отримати випадкові дані з таблиці.
SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails
GROUP BY usr_fk_id
ORDER BY cnt ASC
LIMIT 10
Я думаю, це найкращий спосіб ..
SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no