300-летие битвы при Лесной

В минувшее воскресенье (5 октября 2008) мне довелось побывать в знаменитом месте нашей страны - деревне "Лесная" славгородского района. В этот день там праздновали 300-летие победы над Шведами. Именно в этой деревне находился русский царь Петр I, когда состоялась битва, изменившая ход Северной войны. Эта битва послужила началом бегства шведской армии и окончательного ее разгрома.

Краткая справка
Лесная — белорусская деревня, близ которой 28 сентября 1708 года, во время Северной войны, 12-тысячный летучий отряд Петра I разбил 16-тысячный шведский корпус Левенгаупта. 14 сентября 1708 года Карл XII был вынужден отказаться от немедленного похода на Москву и принять решение о продвижении вглубь Украины. Согласно "журналу Петра Великого", шведы потеряли в этом бою более 9 тыс. человек убитыми и ранеными. Был захвачен огромный обоз с трёхмесячным запасом продовольствия, артиллерией и боеприпасами для армии Карла XII. Особенно отличился Михаил Михайлович Голицын. Пётр I назвал эту победу "матерью Полтавской баталии", поскольку армия Карла осталась без резервов, боеприпасов, что значительно ослабило его силы, а также потому, что битву при Лесной и Полтавскую битву разделяют 9 месяцев (с точностью до одного дня).

Точного количества зрителей не знает никто, но народу было очень много. Жители Славгорода и близлежащих деревень начали собираться задолго до начала праздника. И народ прибывал в течении всего дня. К середине праздника даже стало "тесновато" — количество зрителей уже измерялось тысячами.

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

В боковой части отведенной под празднования территории силами работников отделов культуры нескольких районов были подготовили декорации, отражавшие жизнь и быт людей 18 века. Сами же работники были переодеты в людей того времени. Были тут все — от простых крестьян в затасканных лаптях до князей и министров в парчовых камзолах, от солдат в треуголках до монахинь и попов в рясах.





Инсценировки получились отличные. Зрители могли не только наблюдать за действиями ряженых крестьян и мастеровых, но и сами попробовать молоть зерно, прясть и чесать лен, отведать вместе с гвардейцами царских полков солдатской похлебки, сваренной тут же в большом котле. Чуть дальше работали настоящие кузнецы, делавшие на глазах у зрителей подковы, гончары, лепившие кувшины и вазы. Самые ловкие могли попробовать пострелять из лука в набитое соломой чучело или пометать ножи в деревянную стенку.

Особенно интересно было конечно детям. Для них тут развлечений нашлось предостаточно. Посидеть с графиней в шикарной карете, посмотреть как сельские парни дерутся с помощью рогатин, сесть верхом на древнюю пушку, подержать в руках мушкет, примерить на себя треуголку, попробовать только что испеченных блинов, поглазеть как плетут лапти и корзины...



Взрослым тоже было чем заняться. Помимо районных инсценировок сценическое действие проходило сразу на двух крупных площадках. Играли духовой оркестр и симфонический оркестры, да еще и и отряд барабанщиков. Множество коллективов со всей области показывали свое творчество.



Естественно, фотографироваться можно было везде и со всеми. Даже сам Петр I с удовольствием позировал всем желающим. Правда от самых надоедливых ему приходилось отделываться фразами типа "Извините, дела государственные ждут". ;-)

Чуть в стороне народные умельцы продавали глиняные кувшины и чашки, детские свистульки, плетеные корзины, вышитые картины и еще много всякой всячины. Еще дальше, на краю «зоны праздника», располагались типичные для таких мероприятий ларьки и палатки потребсоюза и коммерсантов, торговавшие в основном напитками и сдобой. На некоторых из них красовались бумажные листки с надписью фломастером: "В связи с праздником продажа спиртных напитков запрещена". :)

Праздник, по задумке организаторов, должен был быть грандиозным. Собственно он таким и вышел бы, если бы организаторы приложили чуть больше усилий. На деле же оказалось, что мероприятие совершенно не подготовлено к сдаче и выглядит весьма халтурно.

Приколы и косяки начались с раннего утра. Генеральная репетиция (как у нас водится) проходила не за день до праздника, а перед самым его началом. Из колонок на сцене вырывались отрепетированнные (и частично заранее записанные) торжественные речи, что вводило в заблуждение как немногочисленных (пока) зрителей, так и самих участников, т.к. звуковое сопровождение никак не вязалось с происходящим на сцене. А там в это время девушки и парни изображали парные танцы на светском балу 18 века, но при этом были одеты во вполне современные джинсы и куртки.

Дальше — хуже.

Прямо на ходу стали ломать сценарий — посадка аллеи началась и закончилась примерно на полтора часа раньше намеченного срока, Крестный Ход опоздал и ведущему пришлось с надрывной торжественностью в голосе трижды его объявлять. Фонограммы были очень плохо сведены (на что ругались даже сами участники вокальной группы), музыка начиналась и обрывалась в серединах фраз, несколько раз врывались совершенно посторонние мелодии.

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

Даже нормальное расположение гостей праздника организаторы не смогли «осилить».

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

Когда объявили прибытие Крестного Хода, народу значительно прибавилось и толпа постепенно стала подбираться в сцене, блокируя собой дорожки. Секьюрити, как в штатском, так и в форме (и тех и других, кстати сказать, на этом празднике было очень-очень много), стали отодвигать толпу от сцены, но никто из них не знал, какую именно дорожку нужно освободить для Крестного Хода, поэтому усердствовали во всех направлениях сразу. Координированием действий, видимо, никто не занимался, т.к. у каждого из охранников была либо рация, либо наушник a-la Agent Smith, но это им совершенно не помогало определиться с направлением приложения усилий.

Еще один ляп вышел, когда какой-то особо шустрый товарищ (скорее всего один из членов орг-комитета) решил, что для улучшения обзора (а заодно и отделения от простых смертных) все высочайшее начальство нужно передвинуть поближе к сцене. Так он и сделал — начальников всяких рангов провели из общей толпы к левому флангу сцены и там поставили лицом к зрителям - этакий президиум получился. Но прикол вышел в том, что участники Крестного Хода зашли с противоположной стороны и в итоге высочайшее начальство совсем ничего не увидело, т.к. было отгорожено самой сценой от всего происходящего.

Во момент появления первых служителей церкви из Крестного Хода я услышал за спиной английскую речь двух мужчин из приглашенных на праздник иностранцев и чуть не заржал. Диалог был примерно таким:
- Нам, наверное, нужно пройти вон туда, к сцене, где находятся все эти важные люди. Пойдем?
- Нет, останемся здесь. Отсюда гораздо лучше видно.

Крестный Ход был красивый, хоть и неорганизованный. Священники в праздничных рясах бегали возле сцены и о чем-то спорили, махая руками. В конце-концов они пришли к какому-то общему решению и участники Хода наконец-то появились перед зрителями. Но их почему-то поставили на правом фланге сцены и народу были видны только первые ряды пришедших. Когда все более-менее расположились, начался молебен в честь погибших участников Северной войны.

После церковных песнопений, по задумке организаторов, от первых рядов кресел должны были пройти ряженые, неся в лампадках огонь к памятнику победы при Лесной (Орлу). Поскольку прямого пути туда гении тротуаров не предусмотрели, то путь получился мягко-говоря кривым. Одновременно с ряжеными, но уже по другому (но не менее кривому) пути, солдаты пытались торжественным шагом пронести венок к тому же самому памятнику. Пытались, потому, что оба эти пути проходили прямо через всю скопившуюся перед сценой многотысячную толпу. Охранники с трудом успевали расчищать перед солдатами дорогу от людей и телевизионщиков. Ряженые пробивались своими силами.

Скажу чуть подробнее о дорожках.

К площадке с креслами перед сценой вели с разных сторон несколько дорожек, которые (как обычно) выкладывали не для удобства хождения людей, а для "красивой картинки при взгляде со спутника". Поначалу народ пытался добраться из пункта А в пункт Б, стараясь ходить по свеже-уложенной к празднику тротуарной плитке и в соответствии с задумкой создателей этого лабиринта. Но позже, наглядевшись на наглых телевизионщиков, тоже начали ходить не так, как нужно, а так, как удобнее. В итоге, к концу праздника, газоны с только-только проросшей травой обрели на своем "лице" новые высококачественные свежепротоптанные маршруты.

Отдельно хочется упомянуть работников разных телеканалов, которых здесь хватало с лихвой.

Телевизионщики — это люди, для которых любая горизонтальная поверхность является полноценной дорогой, даже если там растут кусты, посажены цветы или стоят люди. Они пройдут везде, чего бы это не стоило окружающим. Их профессия вынуждает их лезть наперебой к местам активных действий, попутно расталкивая конкурентов, оттаптывая ноги подвернувшимся зрителям и "случайно" избивая окружающих своими штативами. Я раз шесть получил. Честно скажу, приятного мало.

Но вернемся к празднику.

Описывая организацию сего мероприятия, нельзя не вспомнить и о такой важной вещи, как туалет. Сразу скажу, что мне его посетить не довелось. Во-первых нужды такой не было, а во-вторых потому, что располагался он метров за 300-350 от центра событий. Интересно, кому в голову пришло, что человек, когда ему "припёрло", захочет пройти треть километра, чтобы, отстояв очередь, попасть туалет??? Видимо не найдя ответа на этот вопрос, все нуждающиеся ходили в прямо противоположную сторону — в лес, которого вокруг было предостаточно. Как рассказывали "возвратившиеся из походов", в лесу обнаружилось очень много грибов, в основном моховики, но видели и боровиков. Правда это к делу не относится.

Из всех казусов и ляпов больше всего радости мне доставили пушки времен Северной войны. Их наверное мастерили воспитанники кружка "Сделай сам" местного Дома пионеров. На такую мысль навел материал, из которого они сделаны. Что это за материал, вы не догадаетесь никогда! Они сделаны из пластиковых КАНАЛИЗАЦИОННЫХ труб! И никто даже не потрудился их покрасить... Когда я их фотографировал, рядом проходили какие-то мужики и один другому, показывая на пушку, в шутку задал риторический вопрос: "И как только мы умудрились победу одержать?...".

Вот такой вот вышел праздник.

Сперва вроде все красиво, нарядно, празднично и торжественно. Но потом видишь, как организаторы прямо во время праздника по рации безуспешно пытаются выяснить, куда вести тех или иных гостей; когда фонограмма внезапно обрывается, а танцоры с удивленными лицами замирают в середине своих па и не знают что дальше делать; когда ведущий по три раза читает одно и тоже приветствие, а приветствуемые никак не появляются; когда на каждом шагу натыкаешься на милиционеров с металлоискателями в руках и дежурным вопросом "А что у Вас в сумке" и когда они быстренько отворачиваются как только начинаешь их фотографировать; когда туалет находится за 300 метров от места где он нужен и потому и участники и гости "ходят" в лес; когда на груди у графа из свиты Петра золотой крест сделан из картона и фольги и один из его лучей помят, торчит в сторону и обмотан скотчем (видимо оторвали в толпе); когда солдаты 18 века вместо мушкетов несут в руках современные пневматические ружья; когда пушки "отлиты" из канализационного пластика, а монашки (пусть даже и ряженые) вместе в гвардейцами курят на глазах у всех... Когда все это видишь и слышишь, то лишний раз убеждаешься, что организаторы делали вовсе не праздник, не торжество, а просто банально отрабатывали свою зарплату. Работа не для людей, а ради денег. И ничего удивительного в этом нет - им же платят не за качество, а за "галочку".

И, как ни странно, подход районных коллективов оказался просто разительно отличающимся от области (которая и организовывала основные действия).

Районные отделы культуры, несомненно, намного беднее областных, поэтому им можно простить и разукрашенные деревяшки вместо ружей и неприкрытую скромность в костюмах. Зато они не просто "присутствовали", они действительно играли роли. И надо сказать, что играли их с блеском, с душой. Отдались празднику и отрабатывали по-полной.

Попробуйте целый день не взирая на погоду пролежать на сырой земле, изображая раненого солдата, тогда поймете, чего им это стоило!

А как здорово выглядели крестьяне, истово кланявшиеся и падавшие на колени при виде Петра I; а гвардейцы, кричавшие "Виват государю", чистившие пушки и варившие солдатские щи; а старушки, ткущие лен под старые деревенские песни... Зрители не выдержали и зааплодировали, когда крестьянин, стоя на коленях, начал креститься и с причитаниями целовать краюху черного хлеба, которую только что подарила ему графиня из свиты Петра!

И это не было отрепетировано, т.к. проход царя через районные декорации не был запланирован. Это была настоящая импровизация, профессиональная игра, сама жизнь, если хотите! Если бы областные "мэтры культуры" с таким же желанием и ответственностью отнеслись к поставленной перед ними задаче, то праздник получился бы другим. Совсем другим.

А так зрители, сразу же после возложения венка, стали разбредаться от сцены в разные стороны. И еще до середины праздника, две трети поставленных перед сценой кресел оказались пустыми. Представляю, каково было выступавшим на сцене артистам — все равно, что играть спектакль в пустом зрительном зале. :-(

А люди тем временем пошли смотреть "Город мастеров", фотографироваться с ряжеными, покупать сувениры и есть сладкую вату. Детишки с удовольствием пробовали месить настоящее тесто и молотить пшеницу, смотрели как из куска глины появляются на свет кувшины и чашки, слушали песни старушек у прялок и пробовали солдатские щи. Даже при таком халтурном подходе организаторов, всем посетителям нашлось занятие и развлечение.

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

Остальные фотографии можете просмотреть здесь.


Война попингуям

С сегодняшнего дня начата борьба с попингуями со всяких левых ресурсов. Запущен первый защитный скрипт. Через недельку будут результаты, а пока (для тестирования) в блоге отключены абсолютно все ограничения на доступ по IP и хостам.

СЕО-гуру, добро пожаловать :)


Файлы vs базы данных.

В последнее время все чаще нахожу в интернете статьи, которые расхваливают сайтовые движки, созданные без использования баз данных, т.е. сохраняющие данные в файлах. Непонятно почему, но народ истово верит в то, что именно такой подход (отказ от использования систем управления базами данных и хранение данных в файлах) дает гораздо большую производительность. Стали встречаться даже целые темы в программерских форумах, где сторонники файловых КМС бьются "до последней капли крови" с поклонниками "классического", СУБД-шного подхода.

Странно, но народ в упор не хочет видеть очевидное и с удовольствием витает в облаках собственных заблуждений. Быть может этот пост откроет некоторым глаза на истинное положение вещей. Или, по крайней мере, заставит задуматься...

Давайте рассмотрим процессы, проистекающие на сервере при работе КМС "на файлах" и сравним их с аналогичными процессами при использовании СУБД. В качестве примера «файлового подхода» я буду использовать движок этого блога (Lasto-blog-B), точнее работу его системы статистики. Естественно, точный алгоритм его работы мне не известен (т.к. автор скрывает исходники, шифруя все в байт-код с помощью Zend-Guard), но общие выводы можно сделать просто проанализировав содержимое файлов, хранящих статистические данные.

Кстати, все нижеописанное касается и других поделок от Lasto, которые собирают статистику — сплогов, нового варианта nano-CMS и т.д. Пользователям скриптов других производителей, также использующих файлы в качестве хранилища данных этот пост также должен быть интересен.

Итак, последовательность действий модуля сбора статистики Lasto-блога примерно такова: при обращении серфера к любой странице сайта запускается один и тот же скрипт, который должен собирать статистическую информацию: кто пришел (серфер или бот), откуда он пришел (сайт-источник), куда он пришел (страница нашего сайта) и т.д. Вся эта информация сохраняется в файл и позже, на ее основе, генерируются графики посещаемости по дням, «хит-парад» страниц сайта, сайтов-источников трафика и используемых для просмотра броузеров и прочая мега-полезная отчетность.

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

Особенность хранения данных Lasto-блогом такова, что статистика хранится в нескольких файлах:

  1. hits.http.db — данные о хитах (метка времени хита, IP-адрес источника, User-Agent клиента, хост источника, страница сайта к которой обратился клиент). Кстати, анализируя этот файл можно увидеть, какие страницы сайта проиндексированы какими поисковыми системами (были посещены поисковыми ботами) и когда это произошло. Странно, что Lasto не встроил какого-либо культурного просмотрщика и анализатора этих ценных данных. Или встроил? Но в таком случае, почему об этом нигде не сказано? Стоит задуматься...
  2. hits.rss.db — данные об обращениях RSS-ридеров. В данный момент нам эта инфа не интересна.
  3. hits.mem.db — а вот на этот файл стоит обратить особое внимание. Именно тут собрано самое интересное. В нем хранятся те данные, которые выводятся на странице статистики блога. Будем анализировать работу именно с этим файлом.

Содержимое его представляет собой «серилизованное» отображение многомерного PHP-массива. Структура такова:

  • allsein — данные о заходах с поисковиков по разным запросам
    • хост | искомая фраза
      • дата, количество заходов
      • ...
    • хост | искомая фраза
      • дата, количество заходов
      • ...
    • ...
  • agent — данные о броузерах и ботах
    • user-agent броузера
      • дата, количество заходов
      • ...
    • user-agent броузера
      • дата, количество заходов
      • ...
    • ...
  • pages — данные о посещенных страницах
    • страница
      • дата, количество заходов
      • ...
    • страница
      • дата, количество заходов
      • ...
    • ...
  • rss_agent — данные о запросах от RSS-ридеров
    • user-agent ридера
      • дата, количество заходов
      • ...
    • user-agent ридера
      • дата, количество заходов
      • ...
    • ...
  • source — данные об источниках трафика
    • URL страницы-источника
      • дата, количество заходов
      • ...
    • URL страницы-источника
      • дата, количество заходов
      • ...
    • ...
  • a — общая статистика по ридерам, ботам и т.д. Нас это не интересует.

В качестве дат (видимо для оптимизации) используются целочисленные значения, равные количеству дней, прошедших с некой фиксированной даты (1 января 2000 года). В первом «разделе» (данных о поисковиках и искомых фразах) разделителем данных является символ вертикальной черты.

Таким образом, чтобы узнать, сколько человек посетило страницу stat.html в определенный день, нужно сперва вычислить сколько дней прошло с 1 января 2000 года до искомой даты, затем «заглянуть» в ячейку массива

Пример кода
$ar['pages']['/stat.html'][к-во дней]

Число, которое мы «увидим» в этой ячейке и будет искомым количеством посетителей нашей страницы.

С поисковиками немного сложнее. Нужно сперва собрать «заготовку», состоящую из домена поисковика и искомой фразы, разделенных двумя символами вертикальной черты, а затем просмотреть все элементы массива («раздел» allsein) на предмет ПОЛНОГО строкового равенства (совпадения). Согласитесь, задача не из быстрых.

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

Первое.

При обращении серфера к странице, скрипт собирает всю необходимую информацию (имя страницы, URL страницы-источника, user-agent, дата обращения и т.д.). Этот процесс происходит моментально и заострять внимание на нем не стоит. А вот дальше...

Второе.

Скрипт считывает в память ВЕСЬ файл статистики, не взирая на размер (если посещаемость высокая или статистика собирается за большой срок, то это могут быть десятки или даже сотни мегабайт). И не просто считывает, а делает его «ансерилизацию», если можно этот процесс так назвать. Для тех, кому не совсем понятно, о чем тут идет речь, приведу краткое упрощенное пояснение.

Язык PHP содержит пару функций (serialize и unserialize), предназначенных для преобразования массива в строку и обратно. Первая склеивает все элементы массива (разделяя их спец-символами с технической информацией) и возвращает полученную текстовую строку. Вторая делает обратное преобразование из строки в массив.

Назначение этих функций — упростить передачу массивов по каналам связи, равно как и их сохранение на носителях. Прикол в том, что unserialize восстанавливает точную копию исходного массива, даже если он многомерный, даже если его элементы представляют собой тоже массивы, которые в свою очередь тоже содержат массивы... и т.д. Просто одной командой вы можете превратить ваш супер запутанный массив в текст, а второй точно также вернуть все обратно. Очень удобная возможность.

Но есть и подводный камень. Обе эти операции (особенно вторая) достаточно ресурсоемкие, т.к. приходится парсить (разбирать) огромный объем текста, выискивая в нем те самые спец-символы, по ним восстанавливать значения исходных ячеек и клеить их в результирующий массив. Короче, работы тут много.

Но вернемся к нашей теме. Итак, скрипт загружает текстовый файл и преобразует его в массив. Если вы внимательно прочли предыдущий абзац, то уже должны понимать, что при небольшом количестве элементов в массиве операция проходит относительно быстро. Ну а если это статистика за месяц и при этом с поисковиков в день приходит по несколько сотен человек, да еще по тысяче различных запросов, то получается весьма нехилый объем работы.

Третье.

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

Тут можно немного оптимизировать процесс и сделать обращение вида

Пример кода
$ar['allsein']['google.com||вася пупкин']

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

Четвертое.

Если искомая ячейка существует и найдена, то значение в ней увеличивается на единицу. Если же такой ячейки нет, то ее необходимо создать и поместить в нее единицу. Случаи когда с данной поисковой машины еще не было посетителей и нужно создавать целую ветку массива рассматривать не будем. Нам и описанного вполне хватит.

Пятое.

Серилизация (склейка элементов массива в строку) и перезапись (опять же) ВСЕГО файла статистики.

Я описал не самый худший вариант, т.к. тут затронута обработка данных только из одного «раздела» статистики (а ведь скрипт еще должен скорректировать данные и в остальных), не описан блок, который проверяет доступность сайта для данного юзер-агента и хоста-источника (а он жрет времени тоже немало), не учтены потери на выделение/освобождение памяти и копирование целых веток массива, если автор решил (для упрощения программирования) отделить часть массива например так:

Пример кода
$as = $ar['allsein']; // выделяем данные о заходах с искалок в отдельный массив

Все это уже не столь важно. Главное то, что ПРИ ЛЮБОМ ХИТЕ (даже переходе серфера с одной страницы сайта на другую) происходят ВСЕ описанные операции — чтение, разбор, поиск, склейка, запись и выполняются они над ВСЕМ содержимым файла статистики. А быстрыми их никак уж не назовешь.

Да, да, я знаю о кэшировании файлов. Но и тут не все так просто. За счет кэширования вы выиграете часть времени на чтении/сохранении файла статистики, но как быть с массивом? Его-то никто не прокэширует. А значит парсинг текста и построение массива, равно как и последующая склейка все равно будут выполняться при каждом обращении к скрипту (сайту).

К тому же не стоит забывать, что пока одна копия запущенного скрипта копается в вашем (пусть и прокэшированном) файле, все другие будут тихо и мирно курить в сторонке. Другими словами, пока идет обработка одного посетителя, все остальные будут ждать ибо для них доступ к файлу статистики окажется заблокированным. Очередь, понимаешь...

Теперь взглянем, как эта же задача была бы решена с использованием БД.

Первое на что хотелось бы обратить внимание — это тот факт, что подобную структуру не удастся (по крайней мере целиком) уложить в одну таблицу, а это значит будут использованы несколько связанных таблиц (реляционная структура). Для данного примера также будем рассматривать работу только с одним «разделом» статистики — данных о поисковых запросах.

При нормальном (читай «грамотном») подходе тут будут использованы аж три таблицы: в первой будут храниться хосты поисковиков (по одному на запись), во второй — запросы с хостов (каждый запрос в отдельной записи), ну и в третьей — собственно количество посетителей по дням для каждой из искалок по каждому из запросов. Естественно между ними есть жесткая связь типа «один со многими», т.е. каждой записи из первой таблицы соответствуют несколько записей из второй, каждой из которых соответствуют несколько записей из третьей. Кажется сложным? Нисколько! :-)

Структура, например, такая:

Структура таблиц
Таблица se_hosts
--------------------
ID1 — уникальный числовой номер (используется для связи таблиц) 
Host — имя хоста поисковика

Таблица se_query
---------------------
ID2 — уникальный числовой номер (используется для связи таблиц) 
SH_ID — уникальный номер для ссылки на первую таблицу
Query — текст искомой фразы

Таблица se_hits
-------------------
Q_ID — уникальный номер для ссылки на вторую таблицу
Date — кво-дней с 1 января 2000 года
Hits — количество хитов за этот день

Естественно первая и третья таблицы будут иметь индексы по первым двум полям, а вторая — по всем. Куда ж без них :-)

Итак, серфер пришел, что происходит в скрипте.

Первое.

Сбор информации о серфере. В точности соответствует первому пункту из предыдущего описания.

Второе.

Происходит соединение с БД. Делается это вызовом всего двух функций. По времени — молниеносно.

Третье.

Скрипт должен получить данные из базы о количестве хитов «за сегодня». Вот этот процесс мы и препарируем.

Сразу скажу, что все операции будут выполнены функциями из ОТКОМПИЛИРОВАННЫХ библиотек PHP, поэтому скорость их работы будет максимальной. Ни один скрипт тут рядом не стоял. Но суть не в этом, а в том, что количество этих операций будет намного меньшим. На ОЧЕНЬ много!

Итак, сперва производим поиск в первой таблице.

Если не использовать индексы, то для выполнения этой операции придется провести сравнение имен хоста с содержимым поля Host первой таблицы для части (а в худшем случае всех) записей. И хотя это будет гораздо быстрее чем сканирование массива (за счет работы библиотечных функций) все равно потребует много времени. А вот индексы помогут «надавить на кнопку «турбо».

Еще раз отвлекусь и расскажу немного об индексах.

Индексный файл содержит копию проиндексированного поля (или полей) из таблицы БД, но в отсортированном виде. Благодаря этому можно использовать так называемый бинарный поиск. Работает он так.

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

Для примера, в таблице из 100 записей для поиска любого значения в наихудшем случае понадобится всего 7 сравнений. Быстрее почти в 15 раз!!!! И, повторюсь, это самый ХУДШИЙ случай. В среднем же прирост тридцатикратный!

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

Как нетрудно догадаться поиск во второй таблице нам даст уже экономию времени в 15*10 = 150 раз!!!! Я тут умножил на 10, а не на 15, т.к. во второй таблице при поиске будет использоваться фильтрация по SH_ID (нам же нужны фразы только с найденного хоста, а не все подряд).

Ну и третья таблица — ускорение в 150*10 = 1500 раз!!! И это только на поиске.

Есть естественно и потери. Буду до конца честным и расскажу о них.

Для работы механизма БД, система должна будет загрузить целиком в память три файла индексов. Но, в отличии от ранее рассмотренного варианта работы файлового движка, здесь размер этих файлов в десятки раз меньше. И главное их не нужно парсить, т.к. размер записи в них фиксированный. Т.е. для перехода к нужной записи достаточно просто размер заголовка файла добавить к произведению размера записи в байтах на номер записи и получаем точное смещение от начала файла. Одно сложение и одно умножение — просто ведь. И главное - умопомрачительно быстро!

Четвертое.

После того как мы нашли с помощью индексов нужную запись, ее требуется загрузить в память. Внимание! Нам нужно загрузить ТОЛЬКО ОДНУ ЗАПИСЬ, а вовсе не всю таблицу. В нашем случае размер записи (для третьей таблицы) составляет 12 байт, ведь там только три поля — Q_ID, Date и Hits, каждое из которых представляет собой 32-битное число и занимает 4 байта. Естественно, размер записей в первых двух таблицах (а их нам тоже придется загружать в процессе поиска) немного больше, но все равно он измеряется десятками байт, а не мегабайт!

Запись считали, увеличили на единицу и снова записали НА ТОЖЕ МЕСТО в файле таблицы. Все!

Поскольку записи в нашей третьей таблице (в данном случае) также будут иметь фиксированную длину, то поиск нужной внутри файла также сведется к одному сложению и одному умножению, а уж прочесть и снова записать на тоже место 12 байт — милисекундное дело (даже с учетом автоматической коррекции индексного файла). Да еще про кэширование вспомним :-)

Кстати, если ваш сайт достаточно посещаем, то файл статистики будет расти как на дрожжах и каждое обращение к скрипту будет вызывать чтение/парсинг/поиск/сохранение всех этих десятков мегабайт, а при использовании БД при любом количестве посетителей нам все так же будет нужно читать всего несколько сотен байт (три записи из таблиц), а записать - только 12 байт. Подумайте об этом на досуге.

Ну и конечно не забудьте о том, что поиск можно производить не в каждой таблице по отдельности, а сразу во всех, одной командой:

Пример запроса
SELECT 
   Hits 
FROM 
   se_hosts, se_query, se_hits 
WHERE 
   ID1 = SH_ID AND ID2 = Q_ID AND Date = 3085

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

Что же в итоге?

А итог таков, что пусть мы и поимеем потери на чтении/сохранении индексных файлов все равно получаем примерно тысячекратный прирост в скорости в сравнении с файловым движком. И это при том, что случай был рассмотрен достаточно простой. В реальных же реляционных СУБД, где работают десятки (а то и сотни) связанных между собой таблиц этот выигрыш измеряется уже далеко не тысячами.

Ну и последний гвоздь в гроб файловых КМС.

Задумайтесь вот над чем. В мире существуют тысячи компаний и фирм, которые пишут разные (часто весьма специализированные и уж совсем не дешевые) моторы для сайтов. И все они (моторы) работают ТОЛЬКО с БД. Так неужели во всех этих компаниях работают одни дураки? :-)


Fast: [10] [20]

Этот сайт полностью окупает себя, хотя его ТИЦ=10, а PR=2. Хотите знать, как он это делает? Хотите чтобы Ваш сайт чарез пол-часа тоже начал на полном автопилоте приносить деньги?
Регистрируйся здесь и здесь и начинай получать деньги со своего сайта!