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 шт):

Автор решения: Mike

Эту задачу вообще не надо решать на 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, одним запросом.

→ Ссылка