Allowed memory size - как оптимизировать скрипт
Скрипт выбирает имейлы и сортирует без повторных следований. Проблема начинается, когда в базе собралось только 70шт имейлов. Подскажите, как оптимизировать скрипт, т.к добавление памяти в 1гб не спасает
$db_query = "select id,domain_mail from ".DB_PREF."subcribes where email!='' ";
list($kolvo_item,$one_item) = obr_db_query_select_assoc($db_query);
if($kolvo_item==0)
exit();
$a = array();
foreach($one_item as $d){
$a[$d['id']]=$d['domain_mail'];
}
$b = array_unique($a);
function r($b,$a){
$new_mas = array();
$i=0;
foreach($b as $key=>$uniq){
$k = array_search($uniq,$a);
if($k!==false){
$new_mas[]=$k;
unset($a[$k]);
}else{
unset($b[$i]);
}
if($i==(sizeof($b)-1)){
if(sizeof($a)){
$new_mas=array_merge($new_mas,r($b,$a));
}
}
$i++;
}
return $new_mas;
}
$ext = r($b,$a);
if(sizeof($ext)>0){
$i=0;
foreach($ext as $ay){
$db_query="update ".DB_PREF."subcribes set k='".$i."' where id='".$ay."' ";
$q_ident=obr_db_query($db_query);
$i++;
}
}
Ответы (1 шт):
Эту задачу вообще не надо решать на PHP. Даже хранить в базе номера записей не обязательно. Информацию можно получить прямо из базы данных в нужном порядке
select *
from (
select id,
@domnum:=if(@pdom=domain_mail, @domnum, @domnum+1+(@rnum:=0)) dom_num,
@pdom:=domain_mail domain_mail,
@rnum:=@rnum+1 row_num
from subcribes, (select @rnum:=0, @domnum:=0, @pdom:='') i
where email!=''
order by domain_mail
) x
order by row_num, dom_num
Запрос сортирует данные по домену (который вообще хранить в отдельном поле то же не обязательно, его легко извлечь из email). При смене домена в отсортированных строках, он увеличивает номер домена (@dom_num), таким образом у нас появляются номера у уникальных доменов. Пока домен не меняется переменная @rnum, обозначающая порядковый номер записи с конкретным доменом, увеличивается от строки к строке. При изменении домена @rnum сбрасывается в 0. Таким образом все записи в пределах одного домена нумеруются подряд 1,2,3... Остается пересортировать выборку в порядке номеров записей внутри домена для их чередования и по номеру домена для сохранения максимального расстояния между доменами.
Пример на sqlfiddle.com. Написано для MySQL до 8 версии. В 8 версии появились оконные функции, которые позволяют сделать то же самое более читабельным способом.
P.S. Если вам все таки надо сохранить порядковые номера записей в базе, то их можно легко получить сразу в этом запросе, выполнить его join еще раз к исходной таблице по id и сразу выполнить update, одним запросом.