Высокопроизводительная случайная непоследовательная строка MySQL - PullRequest
3 голосов
/ 19 июня 2011

Я пытаюсь получить случайную строку из таблицы, где данные не меняются. Я читал, что люди пытаются ORDER BY RAND (), что плохо для больших наборов данных и плохо масштабируется.

Я также видел решение, которое заключается в том, чтобы SQL получал случайную строку между минимальным / максимальным диапазоном, например так: FLOOR (MAX (required_id) * RAND), но это будет работать только тогда, когда строки являются последовательными: 1 , 2,3,4,5,6,7,8,9,10.

Данные, которые мне нужно извлечь, не являются последовательными, например: 1,2,3,4,10,11,12,13

Так что я думаю, что есть два решения:

1-е решение: Продолжайте это: ЭТАЖ (МАКС. (Необходимый_идентификатор) * RAND) , пока я не получу строку нужного типа (шанс 1/6)

2-е решение: Создайте дубликат таблицы (так как мои данные никогда не изменятся) примерно так:

temp_id | needed_id | type 
1            1          1
2            4          1
3            7          2
3            8          2

Так что я могу извлечь случайный temp_id, используя этот метод: FLOOR (MAX (temp_id) * RAND) - WHERE type = 1

Что ты думаешь? Скорее всего, 1-е решение будет запущено примерно 6 раз, пока я не получу правильную строку, но во 2-м решении это сработает сразу, но для этого потребуется другая таблица.

Ответы [ 3 ]

4 голосов
/ 19 июня 2011

Ваше утверждение

, но это будет работать только тогда, когда строки являются последовательными:

не совсем правильно: floor() иmax() примеры работают с непоследовательными строками, потому что вы делаете что-то вроде

WHERE id >= FLOOR(RAND()*MAX(id)) LIMIT 1

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

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

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

Поскольку для некоторых неясно, использование функций не является проблемой:

MAX быстро для индексированного поля.Вам не нужно считать все строки (медленно на innoDB), вам просто нужно проследить ваш индекс BTREE, чтобы вы нашли это значение за log времени.Это почти мгновенный

FLOOR - просто математическая функция, которая будет выполнять за линейное время.Так же, как RAND.Имейте в виду, что ORDER BY rand() не медленный из-за rand, а потому, что вам нужно заказать полную таблицу!это не проблема ранда, а порядка.

Теперь у вас есть запрос, который выполняет что-то вроде:

WHERE id >= 48 LIMIT 1

Это, конечно, очень быстро для индексированного поля.Помните, что вы получили 48 (пример), не проводя никакого сканирования таблицы.

1 голос
/ 19 июня 2011

Вам следует прочитать следующее сообщение в блоге Яна Кнешке: ORDER BY RAND ()

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

1 голос
/ 19 июня 2011

$ cnt = количество строк. Это значение может быть кэшировано (и очень рекомендуется, если вы работаете с InnoDB).

$rnd = mt_rand(0,$cnt);

Запрос:

SELECT * FROM `table` WHERE `where_cond`='some_value' LIMIT $rnd,1

Конечно, вы можете выбрать любое значение с любым предложением where, весь трюк в LIMIT $ rnd, 1 part.
Мне нравится этот метод, потому что здесь нет никаких JOIN s.
Кроме того, этот метод может использоваться с последовательными и непоследовательными строками, даже без идентификатора.

...