MySQL быстро выбирает 10 случайных строк из 600К строк

373

Как лучше всего написать запрос, который выбирает 10 строк случайным образом из 60000?

  • 11
    Вот 8 техник ; возможно, один будет хорошо работать в вашем случае.
Теги:
select
random

22 ответа

338
Лучший ответ

Отличная почта, обрабатывающая несколько случаев: от простых до пробелов до неравномерных с пробелами.

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

Это предполагает, что распределение идентификаторов равно, и что в списке идентификаторов могут быть пробелы. См. Статью для более сложных примеров.

  • 46
    Да, если у вас потенциально большие пробелы в идентификаторах, то вероятность случайного выбора вашего самого низкого идентификатора намного ниже, чем вашего высокого идентификатора. На самом деле вероятность того, что первое удостоверение личности после получения самого большого пробела, на самом деле самая высокая. Поэтому это не случайно по определению.
  • 9
    это будет работать, только если ваш столбец идентификатора является последовательным ....
Показать ещё 12 комментариев
265
SELECT column FROM table
ORDER BY RAND()
LIMIT 10

Не эффективное решение, но работает

  • 126
    ORDER BY RAND() относительно медленный
  • 6
    Mateusz - доказательство pls, SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10 занимает 0,0010, без LIMIT 10 - 0,0012 (в этой таблице 3500 слов).
Показать ещё 5 комментариев
20

Самый простой и простой запрос.

SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
  • 13
    К вашему сведению, order by rand() очень медленный, если таблица большая
  • 3
    Иногда МЕДЛЕННОЕ принимается, если я хочу сохранить его ПРОСТОЙ
Показать ещё 1 комментарий
17

Я получаю быстрые запросы (около 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);
?>
  • 11
    Учитывая мою таблицу с более чем 14 миллионами записей, это так же медленно, как ORDER BY RAND()
  • 5
    @snippetsofcode В вашем случае - 400 тыс. строк, которые вы можете использовать просто «ORDER BY rand ()». Ваш трюк с 3 запросами бесполезен. Вы можете переписать его следующим образом: «ВЫБЕРИТЕ идентификатор, URL-адрес СО страниц, ГДЕ ИДЕНТИФИКАЦИЯ (ВЫБЕРИТЕ идентификатор ИЗ СТРАНИЦ ORDER BY rand () LIMIT 10)»
Показать ещё 5 комментариев
12

Из книги:

Выберите случайную строку с использованием смещения

Еще один метод, позволяющий избежать проблем, обнаруженных в предыдущем альтернативы - подсчитывать строки в наборе данных и возвращать случайные число между 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();

Используйте это решение, когда вы не можете принимать смежные ключевые значения и вам нужно убедиться, что каждая строка имеет четную возможность выбора.

  • 0
    для очень больших таблиц SELECT count(*) становится медленным.
8

Простой запрос с отличной производительностью (работает с пробелами):

SELECT * FROM tbl WHERE id IN 
    (SELECT id FROM (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) t)

Два вложенных подзапроса используются, потому что MySQL еще не поддерживает LIMIT в первом.

Это быстро, потому что в фазе сортировки используется только столбец с индексированным идентификатором.

Для взвешенной версии: https://stackoverflow.com/questions/2417621/mysql-select-random-entry-but-weight-towards-certain-entries

5

Как выбрать случайные строки из таблицы:

Отсюда: Выберите случайные строки в MySQL

Быстрое улучшение над "сканированием таблицы" - это использование индекса для выбора случайных идентификаторов.

SELECT *
FROM random, (
        SELECT id AS sid
        FROM random
        ORDER BY RAND( )
        LIMIT 10
    ) tmp
WHERE random.id = tmp.sid;
  • 1
    Это помогает некоторым для MyISAM, но не для InnoDB (при условии, что id является кластеризованным PRIMARY KEY ).
5

Хорошо, если у вас нет пробелов в ваших ключах, и все они численные, вы можете рассчитать случайные числа и выбрать эти строки. но это, вероятно, не так.

Итак, одним из решений было бы следующее:

SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1

который в основном гарантирует, что вы получите случайное число в диапазоне ваших ключей, а затем вы выбираете следующее лучшее, которое больше. вы должны сделать это 10 раз.

однако это НЕ действительно случайно, потому что ваши ключи, скорее всего, не будут распределены равномерно.

Это действительно большая проблема и нелегко решить выполнение всех требований, MySQL rand() - это лучшее, что вы можете получить, если вам действительно нужны 10 случайных строк.

Однако есть и другое решение, которое быстро, но также имеет компромисс, когда дело доходит до случайности, но может вам подойдет. Читайте об этом здесь: Как я могу оптимизировать функцию ORDER BY RAND() MySQL?

Вопрос в том, насколько случайным он вам нужен.

Можете ли вы объяснить немного больше, чтобы я мог дать вам хорошее решение.

Например, у компании, с которой я работал, было решение, в котором они нуждались в абсолютной случайности очень быстро. Они закончили тем, что предварительно заполнили базу данных случайными значениями, которые были выбраны в порядке убывания и снова были установлены на разные случайные значения.

Если вы вряд ли когда-либо обновляетесь, вы также можете заполнить инкрементирующий идентификатор, чтобы у вас не было пробелов, и вы можете просто вычислить случайные ключи перед тем, как выбрать... Это зависит от варианта использования!

  • 0
    Привет джо В этом конкретном случае у ключей не должно быть пробелов, но со временем это может измениться. И пока ваш ответ работает, он сгенерирует случайные 10 строк (при условии, что я напишу предел 10), которые являются последовательными, и я хотел, так сказать, больше случайности. :) Спасибо.
  • 0
    Если вам нужно 10, используйте некое объединение для генерации 10 уникальных строк.
Показать ещё 4 комментария
3

Я использовал этот http://jan.kneschke.de/projects/mysql/order-by-rand/, отправленный Riedsio (я использовал случай хранимой процедуры, которая возвращает одно или несколько случайных значений):

   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 (edit:). Этот столбец добавляется во временную таблицу, созданную подзапросом во время выполнения, влияют на вашу постоянную таблицу):

   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;

В статье я вижу, что он много сделал для оптимизации кода; У меня нет идей, если/насколько мои изменения влияют на производительность, но очень хорошо работают для меня.

  • 0
    «У меня нет идей, если / насколько мои изменения повлияют на производительность» - довольно много. Для @no_gaps_id индекс не может быть использован, поэтому, если вы посмотрите на EXPLAIN для вашего запроса, у вас есть « Using filesort и « Using where (без индекса) для подзапросов», в отличие от исходного запроса.
2

Все лучшие ответы уже отправлены (в основном, ссылки на ссылку http://jan.kneschke.de/projects/mysql/order-by-rand/).

Я хочу указать еще одну возможность ускорения - кешировать. Подумайте, зачем вам нужны случайные строки. Возможно, вы хотите отобразить на веб-сайте какую-нибудь случайную запись или случайное объявление. Если вы получаете 100 req/s, действительно ли нужно, чтобы каждый посетитель получал случайные строки? Обычно полностью кэшировать эти случайные строки X в течение 1 секунды (или даже 10 секунд). Неважно, если 100 уникальных посетителей за одну секунду получают одинаковые случайные сообщения, потому что следующая секунда еще 100 посетителей получат разные посты.

При использовании этого кэширования вы также можете использовать некоторое более медленное решение для получения случайных данных, поскольку оно будет извлекаться из MySQL только один раз в секунду независимо от ваших req/s.

2

Вот смена игры, которая может быть полезной для многих;

У меня есть таблица с 200k строками, с последовательным id, мне нужно было выбрать N случайных строк, поэтому я предпочитаю генерировать случайные значения, основанные на самом большом идентификаторе в таблице, я создал этот script, чтобы узнать, какая из них самая быстрая:

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();

Результаты:

  • Count: 36.8418693542479 ms
  • Макс. 0.241041183472 ms
  • Заказ: 0.216960906982 ms

Основываясь на этих результатах, порядок desc - это самая быстрая операция для получения максимального id,
Вот мой ответ на вопрос:

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 ms (включая все операции на стороне php)

  • 3
    Предлагаем немного увеличить LIMIT - вы можете получить дубликаты.
2

Мне нужен запрос для возврата большого количества случайных строк из довольно большой таблицы. Это то, что я придумал. Сначала получите максимальный идентификатор записи:

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 ГБ, dual 3GHz E5450, а на таблице с 17,361,264 строк он довольно согласован в ~.03 сек /~ 11 сек, чтобы вернуть 1 000 000 строк. (время от MySQL Workbench 6.1, вы также можете использовать CEIL вместо FLOOR во втором выборе в зависимости от ваших предпочтений)

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);
1

Я улучшил ответ @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)
    • Получает случайный id
  • SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 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
  • 0
    Мне нужно 30 случайных записей, поэтому я должен изменить LIMIT 1 на LIMIT 30 везде в запросе
  • 0
    @ Hassaan вы не должны, что изменение LIMIT 1 на LIMIT 30 даст вам 30 записей подряд из случайной точки в таблице. Вместо этого у вас должно быть 30 копий части (SELECT id FROM .... в середине.
Показать ещё 2 комментария
1

Один из способов, которым я нахожу очень хорошо, если есть автогенерированный идентификатор, должен использовать modulo operator '%'. Например, если вам нужно 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;

Это требует полного сканирования, но оно быстрее, чем ORDER BY RAND, и, на мой взгляд, проще понять, чем другие варианты, упомянутые в этом потоке. Кроме того, если система, которая пишет в БД, создает множество рядов в партиях, вы можете не получить такой случайный результат, как ожидаете.

  • 2
    Теперь, когда я так думаю, если вам нужны случайные строки при каждом вызове, это бесполезно. Я думал только о необходимости получить случайные строки из набора, чтобы провести некоторое исследование. Я все еще думаю, что по модулю хорошая вещь, чтобы помочь в другом случае. Вы можете использовать модуль по модулю в качестве фильтра первого прохода, чтобы снизить стоимость операции ORDER BY RAND.
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;
1

Если у вас есть только один Read-Request

Объедините ответ @redsio с temp-table (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 Ответ:

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 left join datatable dt на dt.id = l.data_id где dt.id null,

  • Версия: Дайте вашему набору данных столбец random_sortorder непосредственно в datatable или в постоянной таблице дополнительных datatable_sortorder. Индексируйте эту колонку. Создайте случайное значение в своем приложении (я назову его $rand).

    select l.*
    from datatable l 
    order by abs(random_sortorder - $rand) desc 
    limit 1;
    

Это решение отличает "крайние строки" от самого высокого и младшего случайных_коррекций, поэтому переставляйте их в интервалы (один раз в день).

0

Старый вопрос, но это то, с чем я столкнулся сегодня, желая выбрать случайную страницу. Я решил не использовать ни одного из ответов здесь из-за проблем с производительностью и того факта, что многие из них имеют сильные предубеждения в "случайном". Вот мое решение (используя PHP):

Pages model:

public static function getIDs() {
    $sql  = "SELECT `id` FROM `pages`;";
    $db   = static::getDB();
    $stmt = $db->query($sql);

    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

Pages controller:

public function randomAction() {
    $pages  = Pages::getIDs();
    $random = $pages[rand(0, count($pages))];

    $this->redirect('/' . $random['id'], 307);
}

В основном, все, что он делает, - это получение массива slug-страниц из БД и использование PHP для выбора случайного из возвращаемого массива.

Если вы хотите 10 записей, просто перебирайте массив и удалите выбранные, чтобы избежать дублирования, а затем добавьте их в отдельный массив результатов. Что-то вроде этого:

public static function randomAction() {
    $pages   = Pages::getIDs();
    $count   = count($pages);
    $results = [];

    for($i = 0; $i < 10; $i++) {
        $random = rand(0, $count);
        $count -= 1;

        $results[] = $pages[$random];
        unset($pages[$random]);
    }

    return $results;
}
0

Если вам нужна одна случайная запись (независимо от наличия пробелов между идентификаторами):

PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
        FLOOR(RAND() * COUNT(*))
    FROM `table_name`);

EXECUTE stmt USING @count;

Источник: https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/#comment-1266

0

Я использую этот запрос:

select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10

время запроса: 0,016 с

  • 0
    Имея PK как 1,2,9,15. по вышеуказанному запросу вы получите строки, такие как 4, 7, 14, 11, которых недостаточно!
-3

Используйте простой запрос для получения случайных данных из таблицы.

SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails 
GROUP BY usr_fk_id 
ORDER BY cnt ASC  
LIMIT 10
  • 0
    Если вы хотите использовать какой-либо оператор соединения и где фильтр вы можете использовать.
  • 3
    Из какой части запроса вы получаете случайность?
-4

Вот как я это делаю:

select * 
from table_with_600k_rows
where rand() < 10/600000
limit 10

Мне это нравится, потому что не требует других таблиц, его просто написать, и он очень быстро выполняется.

  • 5
    Это полное сканирование таблицы, и оно не использует никаких индексов. Для больших столов и занятой среды это большой нет, нет.
-5

Я думаю, это лучший возможный способ.

SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no
  • 8
    Черт возьми, это один из худших способов получить случайные строки из таблицы. Это полное сканирование таблицы + сортировка файлов + таблица tmp = плохая производительность.
  • 1
    Помимо производительности, это также далеко не совершенно случайно; вы упорядочиваете по произведению идентификатора и случайного числа, а не просто по случайному числу, что означает, что строки с более низкими идентификаторами будут смещены в сторону более раннего появления в вашем наборе результатов.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню