Быстро выбрать случайный идентификатор из таблицы mysql с миллионами непоследовательных записей

Я огляделся, и, кажется, нет простого способа сделать это. Похоже, что проще просто взять подмножество записей и выполнить всю рандомизацию в коде (perl). Методы, которые я видел в Интернете, кажутся более ориентированными на сотни тысяч, но уж точно не на миллионы.

Таблица, с которой я работаю, имеет 6 миллионов записей (и растет), идентификаторы автоматически увеличиваются, но не всегда сохраняются в таблице (без пропусков).

Я пытался выполнить рекомендованный запрос LIMIT 1, но выполнение запроса занимает вечность — есть ли быстрый способ сделать это, учитывая, что в записи есть пробелы? Я не могу просто взять максимум и рандомизировать диапазон.

Обновление:

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

Или, если я знаю максимум, могу ли я просто выбрать, скажем, 5-ю запись таблицы, не зная, какой это идентификатор. Затем просто захватите идентификатор этой записи.

Обновление:

Этот запрос несколько быстрее. Все еще недостаточно быстро =/

SELECT t.id FROM table t JOIN (SELECT(FLOOR(max(id) * rand())) as maxid FROM table) as tt on t.id >= tt.maxid LIMIT 1

person qodeninja    schedule 09.12.2011    source источник
comment
Что вы имеете в виду под non-gapless? Что есть пробелы?   -  person Matt Fenwick    schedule 09.12.2011
comment
почти уверен, что nodebunny означает типичный индекс автоинкремента, в котором в прошлом были удалены некоторые строки...   -  person    schedule 09.12.2011
comment
Запрос на обновление в вашем сообщении выполняется примерно за 0,005 секунды в моей системе, как быстро вы надеялись, что это будет работать?   -  person    schedule 12.12.2011


Ответы (3)


Да, идея кажется хорошей:

select min(ID), max(ID) from table into @min, @max;
set @range = @max - @min;
set @mr = @min + ((@range / 1000) * (rand() * 1000));
select ID from table
  where ID >= @mr and ID <= @mr + 1000
  order by rand()
  limit 1
--   into @result
;

Может измениться с 1000 на 10000 или сколько угодно по мере необходимости для масштабирования...

РЕДАКТИРОВАТЬ: вы также можете попробовать это:

select ID from table
  where (ID % 1000) = floor(rand() * 1000)
  order by rand()
  limit 1
;

Разделяет его по разным линиям...

РЕДАКТИРОВАТЬ 2:

См.: Как лучше всего выбрать случайную строку из таблицы в MySQL?

Это, вероятно, самый быстрый способ:

select @row := floor(count(*) * rand()) from some_tbl;
select some_ID from some_tbl limit @row, 1;

к сожалению, переменные нельзя использовать в предложении limit, поэтому вам придется использовать динамический запрос, либо записывая строку запроса в код, либо используя PREPARE и EXECUTE. Кроме того, ограничение n, 1 по-прежнему требует сканирования n элементов в таблицу, поэтому в среднем это примерно в два раза быстрее, чем второй метод, указанный выше. (Хотя это, вероятно, более единообразно и гарантирует, что соответствующая строка всегда будет найдена)

person Community    schedule 09.12.2011
comment
Я выполнил этот запрос, но он вернул пустой набор. - person qodeninja; 09.12.2011
comment
Если есть пробелы шире 1000 записей, это может случиться... Каково распределение ваших идентификаторов? - person ; 10.12.2011

SELECT * FROM TABLE ORDER BY RAND() LIMIT 1;

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

person cristian    schedule 09.12.2011
comment
Да, я пробовал это, но для выполнения запроса требуется НАВСЕГДА даже при ограничении 1. - person qodeninja; 09.12.2011
comment
запрос по этой ссылке SELECT t.id FROM table t JOIN (SELECT(FLOOR(max(id) * rand())) as maxid FROM table) as tt on t.id ›= tt.maxid LIMIT 1 немного быстрее - - все еще слишком медленно =/ - person qodeninja; 09.12.2011
comment
Я не думаю, что запрос связанного соединения даст очень однородные случайные результаты, если не будет добавлен порядок по идентификатору? - person ; 10.12.2011

person    schedule
comment
попробуйте выполнить этот запрос на 6 миллионах записей. нужно вечно бежать. - person qodeninja; 09.12.2011