2009-11-05 4 views
1

Я читал, что не стоит запускать SQL-запросы с ORDER BY RAND() в больших базах данных.Случайные записи Mysql PHP

Итак, вот мой снимок при разрыве кода. Код должен выбрать 10 случайных идентификаторов из базы данных, затем сделать второй выбор, чтобы захватить случайные строки.

$sql = "SELECT id FROM table WHERE image != '' 
     ORDER BY id DESC LIMIT 50;"; 

$result = mysql_query($sql); 


while($row = mysql_fetch_array($result)) 
{ 
    foreach($row as $key => $value) 
    { 
     $array[] = $value; 
    } 
} 
$rand_keys = array_rand($array, 10); 

foreach($rand_keys as $value) 
{ 

    $rand_arr[] = $array[$value]; 

} 
$rand_list = implode("," , $rand_arr); 

$sql = "SELECT image FROM table 
     WHERE image != '' 
     AND id IN ($rand_list)"; 
$result = mysql_query($sql); 

Любые предложения по ускорению или упрощению?

ответ

2

Пять Четыре вещи:

  1. Почему вы выборки 50 id сек, если вам нужно всего лишь 12? (Вы выбираете 12 идентификаторов из последних 50 - это имеет смысл, хотя и не является особенно случайным в общем смысле этого слова - это намеренно подмножество ваших строк, из которых вы хотите выбрать случайные строки?).

  2. Профилирован ли SQL-оператор ORDER BY RAND(), чтобы узнать, медленно ли он для вас? Насколько велик ваш набор данных?

  3. В последнем запросе не нужен WHERE image != '', так как вы уже выбрали id s, для которых image != ''.

  4. Почему вы делаете array_rand($array, 10) - вы говорите, что хотите 12 значений?

  5. Вы можете упростить сбор из случайных величин, как это:

$rand_arr = array_rand(array_flip($array), 12);

+0

Я бы действительно избегал «порядка по rand()» в качестве общей привычки. Я видел, как эти массивные таблицы MyISAM заняли всего несколько сотен тысяч строк. –

+0

Давай теперь Доминик. # 3 и # 4 - очевидные ошибки опечатки/забытые идеи. Виноват. # 5 было очень полезно. # 2 на мой взгляд. Я запускаю этот код на общем сервере, и он остановил мой сайт (тот же эффект с ORDER BY rand()). Это заставило меня полностью переосмыслить случайные строки, т.е. слушая случайные изображения. – rrrfusco

0

Я согласен с пунктами 1 и 2 выше - если вы можете выполнить выбор случайных данных в ваше приложение на том же уровне, на котором хранятся данные, тем менее рыхлым вам нужно будет писать, чтобы делать то же самое.

0

Нет особо замечательного способа сделать это элегантно.

Но вы можете взломать его с нескольких направлений. Если ваш набор данных имеет нужный размер (слишком большой для «порядка по rand()», но не слишком большой), имеют последовательные значения id и обычно не удаляют много, вы всегда можете сделать что-то вроде этого:

SELECT MIN(id) as min, MAX(id) as max FROM table 

Создайте некоторое число N случайных чисел между «min» и «max» (включительно). Назовем его 50. Если вы никогда ничего не удаляете из таблицы, N, вероятно, будет 12. Если вы удалите, сделайте некоторую арифметику салфетки и выберете хорошее число. Вероятно, вы ошибаетесь на высокой стороне.

SELECT * FROM table WHERE id IN (<your set of integers>) AND image_id = '' LIMIT 12; 

Проверьте, чтобы у вас было не менее 12 результатов. Если нет, в основном повторяйте и объедините.

Для больших наборов этот метод должен работать намного лучше, чем ORDER BY RAND(), особенно если ваша идентификационная последовательность не очень разрежена.

+0

Мне нравится этот подход, но он подходит только в установке с одним мастером, где auto_increment является монотонным: auto_increment_increment, auto_increment_offset настройки могут распространять эти идентификаторы. –

+0

Хорошая точка. Это работает только до тех пор, пока вы не начнете общаться с несколькими мастерами. – timdev

0

Я бы сосредоточил внимание на точке 5 Доминика как на довольно низком удачном способе получения данных случайным образом. Вы можете sort(), что список идентификаторов также (я считаю, что MySQL обнаруживает это и пропускает сортировку этого списка для вас.)

Существуют и другие методы для больших наборов данных и высокие ставки запросов, которые включают в себя материализованные представления (в основном кэширование таблицы). Вы пытаетесь решить существующую проблему производительности на большом занятом столе?

0

Другой вариант - использовать случайную серированную хэш-функцию и сортировать по ней.

Извлеките максимальную и минимальную идентификаторы для таблицы и используйте функцию rand() PHP для генерации случайного числа между max и min.

Затем используйте это число семян вы хэш-функция .Assume {} соль в SQL означает случайное число, генерируемый PHP

SELECT image FROM table 
WHERE image != '' 
ORDER BY MOD(ABS({salt}-id), MOD({salt}, 10)), ABS({salt}-id)); 

Вы могли бы оптимизировать немного выполняющую MOD ({соль}, 10) вычисление в PHP и передача значения в запросе.

0

Если строка не является чрезмерно большой, я бы профилировал только выбор 50 строк и хранение случайного списка из 12 из них в приложении. Да, это означает, что вы выбрасываете 80% выбранных строк. Когда вы говорите, что 80% из 50 - это действительно преступление? Это тот факт, что SQL не очень хорош.