Следующие решения намного быстрее, чем у Anktastic (count (*) стоит дорого, но если вы можете его кешировать, то разница не должна быть такой большой), что само по себе намного быстрее, чем «случайный порядок» () "когда у вас есть большое количество строк, хотя они имеют несколько неудобств.
Если ваши строки довольно упакованы (т. Е. Несколько удалений), то вы можете сделать следующее (использование (select max(rowid) from foo)+1
вместо max(rowid)+1
дает лучшую производительность, как объяснено в комментариях):
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Если у вас есть дыры, вы иногда будете пытаться выбрать несуществующий rowid, и select вернет пустой набор результатов. Если это неприемлемо, вы можете указать значение по умолчанию, например:
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1)) or rowid = (select max(rowid) from node) order by rowid limit 1;
Это второе решение не идеально: распределение вероятности выше в последнем ряду (тот, у которого самый высокий идентификатор строки), но если вы часто добавляете материал в таблицу, он станет движущейся целью и распределением вероятности должны быть намного лучше.
Еще одно решение: если вы часто выбираете случайные вещи из таблицы с множеством дыр, то вы можете создать таблицу, содержащую строки исходной таблицы, отсортированные в случайном порядке:
create table random_foo(foo_id);
Затем, периодически, заново заполните таблицу random_foo
delete from random_foo;
insert into random_foo select id from foo;
А чтобы выбрать случайную строку, вы можете использовать мой первый метод (здесь нет дыр). Конечно, у этого последнего метода есть некоторые проблемы с параллелизмом, но пересборка random_foo - это операция сопровождения, которая вряд ли случится очень часто.
Тем не менее, еще один способ, который я недавно нашел в списке рассылки *1022*, - это установить триггер на удаление, чтобы переместить строку с наибольшим rowid в текущую удаленную строку, чтобы не было дыр. осталось.
Наконец, обратите внимание, что поведение rowid и целочисленного автоинкремента первичного ключа не одинаково (с rowid, когда вставляется новая строка, выбирается max (rowid) +1, когда это самое высокое значение, которое когда-либо видели +1 для первичного ключа), поэтому последнее решение не будет работать с автоинкрементом в random_foo, но другие методы будут.