быстрый каунтер показов

Статус
В этой теме нельзя размещать новые ответы.

zaartix

Постоялец
Регистрация
15 Май 2006
Сообщения
73
Реакции
27
[FONT=verdana, arial, helvetica]Подскажите плз как Вы обычно делаете счетчик показов, при условии, что нужно максимально уменьшить нагрузку, т.к. показов может быть огромное количество. Как по-вашему, лучше через файлы это организовать или через бд?

имеются ввиду баннерные показы, т.е. надо считать сколько чьих показов было. Вот думаю через primary key и Update field=field+1 или через счетчик в файлах?

Возможно есть другие, менее ресурсоемкие методы?

как вариант еще - создавать в юзерских папках уникальные файлы (touch), потом их считать кроном
[/FONT]
 
У обоих подходов есть + и -.

На файлах flock будет лочить их постоянно и при высокой нагрузке отдача баннеров будет "залипать", пока файл не разлочится. Еще файлы неудобно обрабатывать (надо парсить вручную данные). Для меня на самом деле так и осталось загадкой (со времен работы с Perl) как быстро выполняется flock и не может ли здесь быть коллизии при высокой интенсивности обращений к файлу flock->write->..., что пока flock лочит хэндл у файла кто-то в этот момент просочится и тоже начнет его лочить. Эксперименты не проводил, но как-то было один раз, что содержимое текстового файла обнулилось, хотя честно делал exclusive flock.

В БД удобно вести статистику, лочатся таблицы штатными средствами и пр. Но вот на счет того, что будет работать быстрее, чем через файл - тут есть сомнение. БД - те же файлы + накладные расходы на коннект, транзакции и пр.
 
Я сейчас реализовал так:
PHP:
$file = $baseId.'/'.$adv_id.'_'.$key_id.'.'.uniqid();
if (!touch('/cache/shows/'.$file)) {
    mkdir('/cache/shows/'.$baseId);
    touch('/cache/shows/'.$file);
}
$baseId - id сайта, на котором считаются показы
$adv_id - id объявления
$key_id - id ключевого слова, по которому показ был

само файло пустое

Дальше крон обрабатывает папки

Какие в перспективе у этого метода подводные камни есть? И можно-ли это считать наиболее оптимизированным методом подсчета?
 
zaartix, сколько сижу на никсах и сколько хостингов повидал - нигде в корне не видел папки cache.

Во вторых, папочку 'cache/shows/'.$baseId нужно бы проверять на writeable и при создании проверять записываемость родительской директории.

А то кусками проверочность не рулит. Все-равно, что одевать презерватив, зная что у него 5 верхних сантиметров нет :)
 
zaartix, сколько сижу на никсах и сколько хостингов повидал - нигде в корне не видел папки cache.

Во вторых, папочку 'cache/shows/'.$baseId нужно бы проверять на writeable и при создании проверять записываемость родительской директории.

А то кусками проверочность не рулит. Все-равно, что одевать презерватив, зная что у него 5 верхних сантиметров нет :)
1. cache - это точка монтирования винта на ReiserFS :ah:
2. непонял, проверять возможность записи перед записью? В данном случае это гораздо тормознее, имхо.
Тач возвращает false или true, если true - все ок, если false - либо нет папки, либо нет прав (возможность повтора имен файлов исключаю, т.к. крон отрабатывает каждые 30 минут). Права быть должны при любых раскладах, т.к. папка создавалась самим апачем. А вот отсутствие папки - да, возможно, поэтому и делаем mkdir. Но гораздо чаще будет ситуация, когда папка уже существует, т.е. вцелом скорость будет выше

А вообще какой смысл делать проверки, если я создал специально папку /cache/shows и дал ей 0777 ?
или я вообще не о том? :))

Добавлено через 27 минут
кстати это вообще отдельная тема оптимизации кода, иногда быстрее будет работать, если проверки делать задним числом.

Вот пример из sql (правда используется класс для работы с бд, но по названию функций понятно что они делают :) :(
PHP:
foreach ($t as $adv_id=>$shows) {
    $sql = "update stats set shows='$shows', clicks='$clicks' where baseId='$baseId' and adv_id='$adv_id' and clock='$date'";
    $n = $db->affected_rows($sql);
    if (!$n) {
        $sql = "insert into stats (baseId, adv_id, clock, shows, clicks) values ($baseId,$adv_id,'$date','$shows','{$clicks[$baseId][$adv_id]}')";
        $db->query($sql);
    }
}
этот ведь будет гораздо быстрее работать, нежели:
PHP:
foreach ($t as $adv_id=>$shows) {
    $sql = "select count(*) as num from stats where baseId='$baseId' and adv_id='$adv_id' and clock='$date' ";
    $d=$db->fetch_array($sql);
    if ($d['num']) {
        $sql = "update stats set shows='$shows', clicks='$clicks' where baseId='$baseId' and adv_id='$adv_id' and clock='$date'";
        $db->query($sql);
    } else {
        $sql = "insert into stats (baseId, adv_id, clock, shows, clicks) values ($baseId,$adv_id,'$date','$shows','{$clicks[$baseId][$adv_id]}')";
        $db->query($sql);
    }
}
я прав? или план просрочен оказался? :)
 
1. cache - это точка монтирования винта на ReiserFS
только что проверил - нету ни на одном хосте :)
2. непонял, проверять возможность записи перед записью? В данном случае это гораздо тормознее, имхо.
Аха, сделай chmod или mkdir с кривыми правами без подавления ошибок И посмотри.
PS: для справки, в среднем, операция запуска функции с подавлением ошибки в 7 раз дольше длится ;)

По коду - аха, согласен. Делать запросы к БД в цикле - это очень разумно :D :D :D
PPS: Строки в двойных кавычках - тоже не есть хорошо. На досуге подумай почему ;)

PPPS: хоть с кем-то по оптимизации есть теперь спорить :D
 
1. ну файловая система ведь позволяет создавать папочки :)

2.1. так откуда кривые права???? :) я своими руками создал папку и поставил нужные права. С ней уже ничего не случится.
А что подразумевается под подавлением? error_reporting или @mkdir ? Если у меня error_reporting(0) везде стоит, разве это затормаживает любую функцию сразу в 7 раз????

2.2 насчет запросов к бд.

вот смотри, каждые 30 минут по крону я обхожу папки и удаляю файло, в итоге в памяти массив с данными по показам. Дальше надо запихать это в таблицу статистики.
Как это возможно сделать без foreach ? С учетом, что таблица хранит данные по датам, т.е.

baseId, adv_id, shows, clicks

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

Двойные кавычки - если ты насчет длительности парсинга одиночных и двойных, то этим имхо можно пренебречь в пользу удобства, если строка вне цикла или внутри небольшого цикла.

 
А кривые права - это если создал папочку ручками (владелец - FTP-юзверь), а скрипт не может ее трогать (владелец - NOBODY), если права не 777.

Или, обратная ситуация - вот тебе сразу геморрой и необходимость на проверки. Пишешь класс-враппер для всего этого хозяйства и таскаешь с собой от проекта к проекту - зато сразу забываешь как в оригинале работает :)

По запросам отвечу так: создай в цикле 1 запрос и исполни его . А-ля mysql_query('Insert into... ; Insert into ...; Insert into...')
 
PHP:
session_start();
$_SESSION['count_shows'] = 0;
function countShows() {
if ($shows) $_SESSION['count_shows']++;
$count_s =& $_SESSION['count_shows'];
return $count_s;
}
попробуй модифицировать этот код, мне помог с числом просмотров новостей на сайте
 
PHP:
session_start();
$_SESSION['count_shows'] = 0;
function countShows() {
if ($shows) $_SESSION['count_shows']++;
$count_s =& $_SESSION['count_shows'];
return $count_s;
}
попробуй модифицировать этот код, мне помог с числом просмотров новостей на сайте

Ггы. Зачем ссылка на сессию? Для справки: ссылки эффективно применять только для собственных типов (для нерусских: для своих объектов). Да и то - в PHP5 такая надобность отпала (читай спецификацию).

Если в целях оптимизации делать, то твой вариант явно проигрывает этому:

PHP:
session_start();
	
	function countViews() {
		isset($_SESSION['counts'])? ++$_SESSION['counts']: $_SESSION['counts']=1;
	}
}
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху