Advanced search  

News:

CPG Release 1.6.26
Correct PHP8.2 issues with user and language managers.
Additional fixes for PHP 8.2
Correct PHP8 error with SMF 2.0 bridge.
Correct IPTC supplimental category parsing.
Download and info HERE

Pages: 1 [2]   Go Down

Author Topic: Патч: попытка оптимизации count-запросов  (Read 25225 times)

0 Members and 1 Guest are viewing this topic.

Alex Revo

  • Moderator
  • Coppermine addict
  • ****
  • Offline Offline
  • Posts: 637
  • Инженер человеческих душ
    • Фото Ростова-на-Дону

Держите в курсе.
Logged

kastorskiy

  • Coppermine newbie
  • Offline Offline
  • Posts: 5

Держите в курсе.

Вот что у меня получилось на данный момент (писано на скорую руку, код не причёсан и наличествует харкод там, где следовало бы вынести в настройки, т.к. спешил успеть к ожидаемому наплыву посетителей):

Code: [Select]
<?php
class api_querycache{

private $time_limit;
private $time_now;
private $time_die;

private $result;

function __construct($query$timelimit 60){
global $CONFIG;

$this->result 0;

$this->time_limit $timelimit*60+rand(0,30);
$this->time_now date('U');
$this->time_die $this->time_now+$this->time_limit;

$query_add mysql_real_escape_string($query);

$memcache = new Memcache;
$memcache->connect('localhost'11211);
$memcache->get('extreme_sql_'.md5($query));

if ( ($result $memcache->get('extreme_sql_'.md5($query))) !== false ){
$this->result $result;
}else {
$base mysql_query($query);
$size mysql_num_rows($base);
if ($size == 1){
$tmp mysql_fetch_row($base);
mysql_free_result($base);

$this->result $tmp[0];

$memcache->set('extreme_sql_'.md5($query), $this->resultfalse$this->time_limit);
}
}

return TRUE;
}

function result(){
return $this->result;
}
}

class 
api_delcache {

static private 
$MEMCACHE_SERVERS = array('localhost:11211'); // add more as an array

///////////MEMCACHE FUNCTIONS /////////////////////////////////////////////////////////////////////

private function sendMemcacheCommands($command){
$result = array();

foreach(self::$MEMCACHE_SERVERS as $server){
$strs explode(':',$server);
$host $strs[0];
$port $strs[1];
$result[$server] = self::sendMemcacheCommand($host,$port,$command);
}
return $result;
}
private function 
sendMemcacheCommand($server,$port,$command){

$s = @fsockopen($server,$port);
if (!$s){
return false;
}

fwrite($s$command."\r\n");

$buf='';
while ((!feof($s))) {
$buf .= fgets($s256);
if (strpos($buf,"END\r\n")!==false){ // stat says end
    break;
}
if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these
    break;
}
if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok
    break;
}
}
    
fclose($s);
    return 
self::parseMemcacheResults($buf);
}
private function 
parseMemcacheResults($str){
    
$res = array();
$lines explode("\r\n",$str);
$cnt count($lines);
for($i=0$i$cnt$i++){
    $line $lines[$i];
$l explode(' ',$line,3);
if (count($l)==3){
$res[$l[0]][$l[1]]=$l[2];
if ($l[0]=='VALUE'){ // next line is the value
    $res[$l[0]][$l[1]] = array();
    list ($flag,$size)=explode(' ',$l[2]);
    $res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size);
    $res[$l[0]][$l[1]]['value']=$lines[++$i];
}
}elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){
    return $line;
}
}
return $res;

}

private function 
dumpCacheSlab($server,$slabId,$limit){
    list(
$host,$port) = explode(':',$server);
    
$resp self::sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit);

   return 
$resp;

}

private function 
getCacheItems(){
 
$items self::sendMemcacheCommands('stats items');
 
$serverItems = array();
 
$totalItems = array();
 foreach (
$items as $server=>$itemlist){
    
$serverItems[$server] = array();
    
$totalItems[$server]=0;
    if (!isset(
$itemlist['STAT'])){
        continue;
    }

    
$iteminfo $itemlist['STAT'];

    foreach(
$iteminfo as $keyinfo=>$value){
        if (
preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){
            
$serverItems[$server][$matches[1]][$matches[2]] = $value;
            if (
$matches[2]=='number'){
                
$totalItems[$server] +=$value;
            }
        }
    }
 }
 return array(
'items'=>$serverItems,'counts'=>$totalItems);
}

//////////////////////////////////////////////////////

static function delCache() {
$cacheItemsself::getCacheItems();
$items $cacheItems['items'];
$totals $cacheItems['counts'];

$memcache = new Memcache;
$memcache->connect('localhost'11211);
$memcache->get('extreme_sql_'.md5($query));

foreach($items as $server => $entries) {
        foreach(
$entries as $slabId => $slab) {
    $items self::dumpCacheSlab($server,$slabId,$slab['number']);
            foreach(
$items['ITEM'] as $itemKey=>$itemInfo){
            
if (substr($itemKey012) == 'extreme_sql_') {
            $memcache->delete($itemKey);
                }
            }
}
}
}

}
?>

Первый класс аналогичен сабжевому, только кеш хранится не в базе, а в memcashe. Второй класс служит для очистки кеша, используется так:
Code: [Select]
api_delcache::delCache();
Поскольку в моём случае фотки добавляются редко, я закешировал все агрегатные запросы с таблицами $CONFIG['TABLE_PICTURES'] и $CONFIG['TABLE_ALBUMS']. Т.е. остальные таблицы, например $CONFIG['TABLE_COMMENTS'], пока не кеширую, т.к. обновляются они значительно чаще (но возможно придётся, т.к. $CONFIG['TABLE_COMMENTS'] тоже не маленькая, больше 10000 коментов). А при добавлении фоток очищаю кеш.

Эксперемент показал, что нагрузка таки действительно уменьшилась, и возможно многим такой оптимизации окажется достаточно. Но в моем случае этого всё-таки оказалось недостаточно, наблюдались тормоза в работе галереи. Видимо надо попробовать кешировать не только агрегатные запросы.

Пока продолжаю анализировать лог медленных запросов, чего и другим советую.
Logged
Pages: 1 [2]   Go Up
 

Page created in 0.034 seconds with 20 queries.