Случайный контент окончательный метод [дубликат]

Я столкнулся с еще более серьезной проблемой при поиске текста для таких слов, как .NET, C++, C# и C. Вы могли бы подумать, что программисты будут лучше знать, чем назвать язык, что трудно написать для регулярных выражений.

В любом случае, это то, что я узнал (в основном обобщенный из http: // www.regular-expressions.info , который является отличным сайтом): В большинстве вариантов регулярного выражения символы, которые сопоставляются с коротким символьным классом \w, являются символами, которые рассматриваются как словавые символы по слову границы. Java является исключением. Java поддерживает Unicode для \b, но не для \w. (Я уверен, что в то время была веская причина).

\w означает «символ слова». Он всегда соответствует символам ASCII [A-Za-z0-9_]. Обратите внимание на включение подчеркивания и цифр (но не тире!). В большинстве вариантов, поддерживающих Unicode, \w содержит много символов из других скриптов. Существует много несогласованности относительно того, какие символы фактически включены. Буквы и цифры из алфавитных сценариев и идеографов, как правило, включены. Пунктуация соединителя, отличная от символа подчеркивания, и числовые символы, которые не являются цифрами, могут быть включены или не включены. XML Schema и XPath даже включают все символы в \w. Но Java, JavaScript и PCRE соответствуют только символам ASCII с \w.

Именно поэтому Java-регулярное выражение ищет C++, C# или .NET (даже если вы помните, чтобы избежать период и плюсы) прикручиваются \b.

Примечание. Я не уверен, что делать с ошибками в тексте, например, когда кто-то не помещает пробел после периода в конце предложения. Я разрешал это, но я не уверен, что это обязательно правильно.

В любом случае, на Java, если вы ищете текст для этих странных языков, вам нужно заменить \b с символами пробела и препинания до и после. Например:

public static String grep(String regexp, String multiLineStringToSearch) {
    String result = "";
    String[] lines = multiLineStringToSearch.split("\\n");
    Pattern pattern = Pattern.compile(regexp);
    for (String line : lines) {
        Matcher matcher = pattern.matcher(line);
        if (matcher.find()) {
            result = result + "\n" + line;
        }
    }
    return result.trim();
}

Затем в тестовой или основной функции:

    String beforeWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|^)";   
    String afterWord =  "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|$)";
    text = "Programming in C, (C++) C#, Java, and .NET.";
    System.out.println("text="+text);
    // Here is where Java word boundaries do not work correctly on "cutesy" computer language names.  
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for .NET="+ grep("\\b\\.NET\\b", text));
    System.out.println("Should find: grep exactly for .NET="+ grep(beforeWord+"\\.NET"+afterWord, text));
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for C#="+ grep("\\bC#\\b", text));
    System.out.println("Should find: grep exactly for C#="+ grep("C#"+afterWord, text));
    System.out.println("Bad word boundary can't find because of Java:grep with word boundary for C++="+ grep("\\bC\\+\\+\\b", text));
    System.out.println("Should find: grep exactly for C++="+ grep(beforeWord+"C\\+\\+"+afterWord, text));

    System.out.println("Should find: grep with word boundary for Java="+ grep("\\bJava\\b", text));
    System.out.println("Should find: grep for case-insensitive java="+ grep("?i)\\bjava\\b", text));
    System.out.println("Should find: grep with word boundary for C="+ grep("\\bC\\b", text));  // Works Ok for this example, but see below
    // Because of the stupid too-short cutsey name, searches find stuff it shouldn't.
    text = "Worked on C&O (Chesapeake and Ohio) Canal when I was younger; more recently developed in Lisp.";
    System.out.println("text="+text);
    System.out.println("Bad word boundary because of C name: grep with word boundary for C="+ grep("\\bC\\b", text));
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
    // Make sure the first and last cases work OK.

    text = "C is a language that should have been named differently.";
    System.out.println("text="+text);
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

    text = "One language that should have been named differently is C";
    System.out.println("text="+text);
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

    //Make sure we don't get false positives
    text = "The letter 'c' can be hard as in Cat, or soft as in Cindy. Computer languages should not require disambiguation (e.g. Ruby, Python vs. Fortran, Hadoop)";
    System.out.println("text="+text);
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

P.S. Моя благодарность http://regexpal.com/ , без которой мир регулярных выражений был бы очень несчастным!

399
задан hims056 19 December 2012 в 08:07
поделиться

22 ответа

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

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

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

338
ответ дан Squazz 1 September 2018 в 06:49
поделиться

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

SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails 
GROUP BY usr_fk_id 
ORDER BY cnt ASC  
LIMIT 10
-2
ответ дан Arun A S 1 September 2018 в 06:49
поделиться

Я получаю быстрые запросы (около 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);
?>
16
ответ дан Benjamin 1 September 2018 в 06:49
поделиться

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

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

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

-3
ответ дан Bernardo Siu 1 September 2018 в 06:49
поделиться

Я использовал этот 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;

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

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

3
ответ дан bogdan 1 September 2018 в 06:49
поделиться

Старый вопрос, но это то, с чем я столкнулся сегодня, желая выбрать случайную страницу. Я решил не использовать ни одного из ответов здесь из-за проблем с производительностью и того факта, что многие из них имеют сильные предубеждения в «случайном». Вот мое решение (используя 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);
}

В принципе, все, что он делает, это получить массив пулов страниц из БД и использование 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
ответ дан Chris Clower 1 September 2018 в 06:49
поделиться

Я просмотрел все ответы, и я не думаю, что кто-либо упоминает эту возможность вообще, и я не уверен, почему.

Если вы хотите предельно простоту и скорость, незначительная стоимость, то для меня, похоже, имеет смысл хранить случайное число против каждой строки в БД. Просто создайте дополнительный столбец random_number и установите по умолчанию значение RAND(). Создайте индекс в этом столбце.

Затем, когда вы хотите получить строку, генерируйте случайное число в вашем коде (PHP, Perl, что угодно) и сравните это с столбцом.

SELECT FROM tbl WHERE random_number >= :random LIMIT 1

Я думаю, хотя это очень удобно для одной строки, для десяти строк, таких как OP, вы должны были бы назвать это десять раз (или придумать умную настройку, которая ускользает от меня сразу )

0
ответ дан Codemonkey 1 September 2018 в 06:49
поделиться

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

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

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

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

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

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

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

Вопрос в том, насколько вам это необходимо.

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

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

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

10
ответ дан Community 1 September 2018 в 06:49
поделиться

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

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

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

SELECT *
FROM random, (
        SELECT id AS sid
        FROM random
        ORDER BY RAND( )
        LIMIT 10
    ) tmp
WHERE random.id = tmp.sid;
7
ответ дан Eric Leschinski 1 September 2018 в 06:49
поделиться

Если у вас есть только один 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;

Если у вас много запросов на чтение

  1. Версия: вы можете сохранить постоянную таблицу tmp_randorder, называть ее datatable_idlist. Восстановите эту таблицу в определенные интервалы (день, час), так как она также получит дыры. Если ваша таблица становится очень большой, вы можете также пополнить отверстия, чтобы выбрать l.data_id как целое из datatable_idlist l left join datatable dt на dt.id = l.data_id, где dt.id равно null;
  2. Версия: Дать ваш Dataset столбец random_sortorder либо непосредственно в datatable, либо в постоянной дополнительной таблице datatable_sortorder. Индексируйте эту колонку. Создайте случайное значение в своем приложении (я назову его $rand).
    select l.*
    from datatable l 
    order by abs(random_sortorder - $rand) desc 
    limit 1;
    

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

1
ответ дан flaschenpost 1 September 2018 в 06:49
поделиться

Я улучшил ответ @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)

Позвольте мне распаковать то, что происходит.

  1. @max := (SELECT MAX(id) FROM table) Я вычисляю и сохраняю максимум. Для очень больших таблиц есть небольшая накладная плата для вычисления MAX(id) каждый раз, когда вам нужна строка
  2. SELECT FLOOR(rand() * @max) + 1 as rand) Получает случайный id
  3. 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
1
ответ дан Hans Z 1 September 2018 в 06:49
поделиться

I Используйте этот запрос:

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

время запроса: 0.016s

-1
ответ дан josejavierfm 1 September 2018 в 06:49
поделиться

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

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 / выбор-а-случайные записи с использованием-MySQL-тесты-результатов / # комментарий-1266

1
ответ дан Junaid Atari 1 September 2018 в 06:49
поделиться

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

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

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

2
ответ дан Marki555 1 September 2018 в 06:49
поделиться

Его очень простой и однострочный запрос.

SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
20
ответ дан Muhammad Azeem 1 September 2018 в 06:49
поделиться

Один из способов, которым я нахожу очень хорошо, если есть автогенерированный идентификатор, заключается в использовании оператора modulo «%». Например, если вам нужно 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, и, на мой взгляд, проще понять, чем другие варианты, упомянутые в этот поток. Кроме того, если система, которая записывает в БД, создает множество рядов в партиях, вы не можете получить такой случайный результат, как ожидаете.

1
ответ дан Nicolas Cohen 1 September 2018 в 06:49
поделиться
SELECT column FROM table
ORDER BY RAND()
LIMIT 10

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

288
ответ дан Preetam Purbia 1 September 2018 в 06:49
поделиться

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

SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no
-4
ответ дан Ritesh Patadiya 1 September 2018 в 06:49
поделиться

Другим простым решением было бы ранжирование строк и выборка одного из них случайным образом, и с помощью этого решения вам не нужно будет иметь столбец «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
ответ дан sactiw 1 September 2018 в 06:49
поделиться

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

У меня есть таблица с 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();

Результаты:

  • Count: 36.8418693542479 ms
  • Max: 0.241041183472 ms
  • Порядок: 0.216960906982 ms

Основываясь на этих результатах, order 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 мс (включая все операции на стороне php)

2
ответ дан Toni Almeida 1 September 2018 в 06:49
поделиться

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

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);
3
ответ дан user2406626 1 September 2018 в 06:49
поделиться

Из книги:

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

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

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

12
ответ дан zloctb 1 September 2018 в 06:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: