За чистый и ясный код!

Статьи на тему программирования под веб, используя PHP, MySQL, Jquery и многое другое

Поиск узких мест при создании сайтов на фреймверке Kohana

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

Kohana Debug Toolbar (KDT)

KDT портировал на  Kohana3 Иван Броткин почитать можно тут, также была статья на Хабре по работе с этим инструментом, правда в Kоhana версии 2.3.x .

С версии 2 было много изменений о которых я и опишу.

 

  1. Версия Kohana — (блин букву на картинке пропустил), при клике на номеру версии переход на страницу фреймверка;
  2. Время выполнения — показывает затраченное время на выполнения различных частей сайта, также показывает метки времени поставленные пользователем;
  3. Затраченная память — как и в предыдущем параметре показывает сколько памяти «съел» каждый кусок сайта;
  4. Кол-во запросов к БД — показывает все запросы выполненные на странице, времени выполнения, используемой памяти. Также может разделять запросы по подключению к разным БД, используя разные секции конфига БД (по-умолчанию default);
  5. Глобальные переменные — $_GET, $_POST etc, показывает все их значения, на момент построения страницы;
  6. Аякс запросы — показывает ко-во аякс запросов на странице;
  7. Подключённые файлы — показывает файлы с полным путём, размером и кол-вом строк в файле;
  8. Подключённые модули — показывает какие модули были подключены при выполнении страницы и их путь на серваке;
  9. Роуты — показывает все роуты в системе и жирным выделяет используемый роутер;
  10. Пользовательские переменные — никогда не юзал, сказать ничего не могу;
  11. Выравнивание и закрытие KDT — думаю название говорит само за себя.

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

Пощупать можно по ссылке внизу статьи.

Profiler

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

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

FirePHP

Еще один способ посмотреть данные, для этого надо установить в FireFox расширения FirePHP и FireBug. Скачать отсюда  модуль FirePHP  немного обработать напильником (там старая версия)  и у вас получится передача данных в заголовках (headers) и в панели фаербага будет видно следующее

Если посмотреть внимательно, то в этот инструмент модуль KDT может также высылать свою инфу. Честно сказать, мне этот инструмент ничего нового не принес, просто еще один способ получения инфы. Кому нужно могу выслать готовый модуль на почту.

SQLmon

Ещё один инструмент, изюминкой которого, по моему мнению, является разъяснения запросов, explain был написан программистов Владимиром, вот ссылка на статью посвящённую этому инструменту.

Единственное для работы в версии 3.2 я в нём внёс некую коррективу в класс Kohana_Database_SqlMon изменив набор аргументов метода query:

class Kohana_Database_SqlMon extends Kohana_Database_MySQL
{
это
public function query($type, $sql, $as_object)
заменил на это
public function query($type, $sql, $as_object = FALSE, array $params = NULL)

И все работает.

Все инструменты с примерами можно посмотреть тут.

Статья просмотренна 477449 раз, зашло посетителей 40448

Высокая нагрузка сайта написанного на Kohana

Октябрь29

Вступление

«A very fast framework. Benchmarking a framework is hard and rarely reflects the real world, but Kohana is very efficient and carefully optimized for real world usage.»

Так написано на главной странице этого фреймворка, так ли это? Да так, но с напильничком. Немного о проблеме.
У меня был заказ от студии creative-cafe.ru на один высоконагруженный проект http://www.jv.ru/longlivers, вроде на девелоперской машине работает хорошо, быстро. Показатели загрузки главной страницы с отколюченными системами кеширования под Ubuntu 11.10 показывают 1-2 секунды (после оптимизации 30-50ms), под виндой вообще караул 4-5 секунд, причём одно и тоже железо, просто ОСи разные, но в этой статье не об этом (советую работать под ОСью приближенной к продакшену). Так вот показатели вроде неплохо 1-2 секунды, а на продакшене сервер то мощнее будет, там вообще летает, но до некоторых действия. Когда заказчик нажал F5 и подержал так секунд 10, сервер смог загрузить контент только через 30 сек… Всего было отправлено около 200-300 запросов… Это уже не порядок, а что если 1000 зайдет?

Конечно о тестировании высокой нагрузки сказать ничего не могу, т.к. не сталкивался с такими тестами, если кто-то что-то знает отпишитесь в комментариях. Естественно я знаю о проблеме и что надо делать, и так начнём.

Инструменты для оптимизации

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

Оптимизация БД

БД в проекте вообще маленькая 15 таблиц, она полностью сделана по нормализации, поставлены ключи в тех местах которые нужны, оптимизированы все запросы, запросы которые «системные» (об этом позже) закешированы. Всего на главной выполняется 22 запроса после кеширования и занимает это вообще мелочь 2.5 ms.
Для оптимизации таблицы могу порекомендовать юзать функию explain, почитать что такое нормализация таблиц БД и ещё рекомендую настроить и смотреть лог медленных запросов, он будет актуальным когда база наберет инфу и тогда можно смотреть какой запрос превышает порог медленных запросов. Но все это не относится к фреймверкам, это просто понимание работы БД.

Чем же нам может помочь фреймворк? Для работы с БД я использовал ORM, как я мог заметить при работе с разными фреймами, все ОРМы считывают структуры таблицы, что Zend Framework, что Kohana. И так зачем нам каждый раз считывать структуру таблиц, если они крайне редко меняются особенно на продакшене? Для этого надо закешировать эту информацию, ниже приведён класс который позволяет это сделать:

<?php defined('SYSPATH') OR die('No direct access allowed.');
/**
 * Перекрытие метода получения данных о структуре таблиц 
 *
 * @package	Core
 * @author Maxim Nagaychenko <maxnag [at] meta.ua>
 * @copyright  Maxim Nagaychenko
 * @filesource
 */
class ORM extends Kohana_ORM
{
	/**
	 * Кеширование структуры таблицы
	 * 
	 * @see Kohana_ORM::list_columns()
	 * @return array 
	 */
	public function list_columns()
	{
	    $cache_lifetime=360000; // 100 часов
	    $cache_key = $this->_table_name ."_structure";
	    $result = Cache::instance()->get($cache_key);
	    
	    if ($result) {
	        $columns_data = $result;
	    }
	 
	    if( !isset($columns_data)) {
	        $columns_data = $this->_db->list_columns($this->_table_name);
	        Cache::instance()->set($cache_key, $columns_data, $cache_lifetime);
	    }

	    return $columns_data;
	}
}

Данный метод я положил в папку application/classes/orm.php в моделях которые используют наследование от ORM я ничего не менял, т.е.

class Model_Contest extends ORM {
....
}

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

Конечно сам ОРМ нагружает систему, т.к. выдает все данные запроса, т.е. select * from, а как сделать если надо только определённые поля? Я не знаю, кто знает подскажите. Особенно это заметно на большой таблице с большим кол-вом полей и забором большого кол-во данных. Тут конечно больше проблем в БД, но всё же ОРМу тяжко. Использовать простые запросы куда менее ресурсоёмко, но увы проигрываем в простоте построения запросов.

Стили и скрипты

Лучше если все стили и скрипты будут сложены в одном файле соот., это сэкономит на кол-ве запросов к серверу, что тоже время. Например я на главной использую 8 файлов-скриптов, 2 файла стилей, отсюда дополнительно 10 запросов на сервер. Как можно с этим бороться? Для этого я использую модуль Minify. У него хорошая документация, легко подключается к системе и выполняет свои функции, кроме «слепки» файлов в один, он еще может удалять комментарии и различные спецсимволы.

Кеширование

Для системы кеширования я выбрал memcache, он позволяет сохранять данные по типу key=>value, хранит их в ОЗУ сервера, соответственно работа с этим типом кеша очень быстрая.

Что я храню в мемкеше? Данные по структуре таблиц, которые требуются для работы с ORM, различные настройки сайта, которые меняются крайне редко, это у меня кол-во записей на странице, для каждого в раздела, контактные данные для отправки писем. Также по всему сайту есть сквозной блок новостей, которые показывает последние две новости проекта, вот такие блоки я и закешировал, при изменении данных новостей, кеш переписывается на новый. На сайте имеются много модальных окон, они построены на основе jQueryUI, а контент (формы, тексты) строятся каждый раз при создании страницы, а как часто люди при просмотре сайта нажимают зайти, зарегистрироваться и тд? Думаю намного реже, чем просто смотрят контекстные страницы, поэтому html этих окон закеширован, что дало тоже большой прирост. Прирост дало то, что контент в эти окна грузятся с БД, а формы строятся с помощью класса Form, что сильно нагружает систему.

Отказаться где можно от использования ООП

Да, это так. Программы разработанные на ООП занимают в памяти куда больше места, чем обычные процедурные, и на больших проектах заметны тормоза. Ниже я привел примеры построения формы на чистом XHTML и с использование класса Form. По своей сути этот класс всего лишь обёртка над тегами формы, можно обойтись и без него, но честно труднее, т.к. валидация, всякие изменения хорошо работают с этим классом. Также есть класс URL которые выдает полный урл, конечно можно без него обойтись, кто мешает в теге ссылки написать относительный урл? Но этот фреймверк, он должен быть универсальным, поэтому исключить этот класс нельзя. В чем же заключается его универсальность? Например сегодня ваш сайт живет по адресу http://example.com, потом вы решили его перенести по пути http://example.com/blog, что же будет без использования класса URL, понадобится все ссылки перебить с / на /blog, а представляете сколько их может быть по всем файлам, также менять роутеры и прочее… беда, а вот с использованием этого класса позволяет всего навсего в файлах bootstrap.php и .haccess изменить урл сайта на нужный вам и все ссылки тут же преобразуются. Тут надо и делать выбор или писать без этого класса, выигрыш в скорости или с ним, но тогда потеря производительности, но универсальность. Думайте сами.

Конкатенация содержимого файлов

При работе сайта по управлением Kohana подключается множество файлов через внутренний автолоадер, только системных файлов порядка 70, остальные сильно зависят от подключённых модулей и достигает до 260 на главной странице сайта. Время которое мой локальный комп подключет эти файлы вообще смешное 5 ms, я бы и не обращал на это внимание, но заказчик попросил объединить это все в один файл и уменьшить кол-во инклюдов… Ну что тут скажешь, он платит.
Нашелся этот модуль у одного блогера, описание и проблема решения тут SuperCache. После его применения кол-во фалов сократилось до 75 c 260.

Инструменты профайлинга

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

Второй инструмент это класс Profiler и он встроен в ядро фреймворка. Как раз с помощью этого класса я смог поставить точки в разных частях сайта и посмотреть какая часть сколько времени отрабатывается. Например интересует сколько времени занимает прорисовка формы, берем ставим точку запуска в начале формы и в конце точку остановки. Профайлер нам выдаст сколько времени это заняло, как раз это и мне помогла найти «узкие» места. Как работать с профайлером опишу в другой статье.

Примеры

Я тут приведу всего один пример, который покажет 2 одинаковых формы (просто прорисовка без логики работы). В самом низу формы как раз расположен профайлер, в нём есть раздел «Построение формы» и в нем два пункта, как можно убедится результаты ощутимы — построение на чистом html в тысячи раз быстрее чем строить тоже самое на ООП, особенно если представить это в рамках большого проекта. Обратите внимание еще на кол-во используемой памяти.
Также в верхнем правом углу расположен DebugToolbar, там тоже есть нужная инфа для работы.

Пример

PS Нужны скидки на товары или услуги? Приобретайте купоны на www.newsavings.ca, которые помогут Вам сэкономить ваши средства.

Статья просмотренна 485505 раз, зашло посетителей 42798

Работа с realtime индексами (RT) в поисковом движке Sphinx

Сентябрь18
Добро пожаловать на форум про php, интерсные статьи, задачи и обзоры.

Кто не знает что такое Sphinx

Сфинк — это бесплатный полнотекстовый поисковый движок. С быстрой индексацией документов, стоп-словами, умеет интегрироваться с самыми известными БД Mysql, MsSql, Oracle и тд, также имеет АПИ с популярными языками программирования PHP, Perl, Java и тд. Также имеет поддержку SQL синтаксиса. Более подробнее тут.

Версии поисковика

На сегодня последняя версия 2.0.1, не смотрите что она бета, на этом проекте беты очень стабильны.

Также есть версия 1.10, из неё родилась версия выше, а эту отправили в утиль архив.

К стабильной версии относится 0.9.9

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

Начиная с версии 1.10 появились relatime индексы. Это индексы которые изменяются «на лету», т.е. не нужно делать промежуточные индексы и через какое-то время сливать их с главным индексом.

Во всех версия появилась возможность создавать таблицу в MySQL 5.x с движком SPHINX (Sphinx storage engine), т.е. появилась возможность обращаться к данным поискового индекса через SQL запросы к БД MySQl, более подробно тут

Также во всех версиях доступен API.

Более подробно обращайтесь к разным блогам, документации поисково движка.

Какие бывают индексы

Есть обычный индекс с ним неотъемлемо связан дельта индекс, который затем сливается с индексом (merge).
Чем мне этот тип индекса не понравился. Например, у вас есть БД с огромным кол-во записей (новостная система) и каждый день добавляется по 500-1000 новостей, вот тут необходимо производить множество операций, создавать описание главного индекса, также создавать описание вспомогательного индекса, который будет потом добавлять в главный индекс, т.е. небольшое кол-во данных которые пришли за указанное вами время. Затем необходимо запускать процедуру объединения дельта индекса и главного индекса. Получается ситуация, что добавили новость в БД, а она появится в поисковом индексе только когда произойдет объединение индексов, время конечно задаёт программер, но все таки это какой-то промежуток + плюс куча операций.

С версии 1.10 появились «realtime» (RT) индексы, они работают только с SphinxQL, т.е. заполнение данных в индекс, удаление, изменение происходит по средству SQL запросов (очень хорошо описано тут). Самая ВАЖНАЯ особенность этого типа индекса, то что данные попадают в тот же момент, когда они попадают в БД (вам нужно просто создать два запроса, один в БД, а другой в индекс Сфинкса). Этот индекс мне очень понравился и я его с успехом применил в одном проекте. Вот как с ним работать я бы и хотел поведать в этой статье.

Работа с RealTime Index

Лучше всего показывать на реальном примере, дабы сразу видеть результаты.

Создаем БД MySQL и в ней таблицу новостей

CREATE TABLE news (
	id INT(11) NOT NULL AUTO_INCREMENT,
	date TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
	title VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	descr VARCHAR(2000) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	keywords VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	text VARCHAR(16000) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	`show` TINYINT(1) NOT NULL DEFAULT '0',
	PRIMARY KEY (id)
)
COMMENT='Новости'
COLLATE='utf8_unicode_ci'
ENGINE=MyISAM
AUTO_INCREMENT=1;

Далее создадим конфиг для поисковика для индекса новостей.

index rt_news
{
	type 					= rt
	path 					= f:/sphinx/data/rt_news
	rt_field				= title
	rt_attr_timestamp		= date
	rt_field				= descr
	rt_field				= keywords
	rt_field				= text
	rt_attr_uint			= view

	rt_attr_string			= title
	rt_attr_string			= descr
	rt_attr_string			= keywords
	rt_attr_string			= text

	docinfo					= extern
	morphology				= stem_enru
	min_word_len			= 1
	html_strip				= 1
	charset_type			= utf-8
	enable_star				= 1
	rt_mem_limit			= 256M
}

searchd
{
	listen			= 127.0.0.1:9306:mysql41
	log				= f:/sphinx/searchd.log
	query_log		= f:/sphinx/query.log
	pid_file		= f:/sphinx/searchd.pid
	read_timeout	= 5
	max_children	= 30
	max_matches		= 1000
	workers			= threads # for RT to work
}

В конфиге есть две обязательные секциии index нужна для описания индекса и searchd тут описываются настройки самого демона (службы) поисковика.

Разберем.

После названия секции index идет название индекса (произвольное [a-zA-Z0-9_] возможно есть еще знаки, но думаю этого достаточно для описания), далее идет описание самого индекса, указывается тип индекса, путь где будет хранится индекс, лучше пусть путь будет на латинице, т.к. используется кодировка UTF-8 и под виндой русское название будет в кракозябрах. Далее идет описание полей и их тип подробнее о различных типах тут, далее идут управляющие команды индексом, какую морфологию использовать, сколько памяти отводить, какая кодировка и тд, есть еще куча настроек, но она специфична и зависит уже от поставленных задач, обращайтесь к документации.

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

Имея конфиг запустим поисковик, буду показывать все в командной строки для наглядности

F:\sphinx\bin>searchd.exe --config f:\Sphinx\sphinx.conf
Sphinx 2.0.1-beta (r2792)
Copyright (c) 2001-2011, Andrew Aksyonoff
Copyright (c) 2008-2011, Sphinx Technologies Inc (http://sphinxsearch.com)

using config file 'f:\Sphinx\sphinx.conf'...
listening on 127.0.0.1:9306
precaching index 'rt_news'
precached 1 indexes in 0.011 sec

Служба запущена и показывает что слушает Mysql на порту 9306 и создан один индекс с названием rt_news.

Добавление данных в БД и индекс

Пришло время заполнить БД и индекс данными. Подключаемя к поисковику через mysql на порту 9306

F:\Zend\MySQL 5.1.52\bin>mysql -P9306
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 2.0.1-beta (r2792)

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

Запишем просто одну запись в БД (в примере только запрос, как его исполнять решать вам) и одну запись в поисковый индекс.

# В БД
INSERT INTO `news` (`id`, `date`, `title`, `descr`, `keywords`, `text`, `show`) VALUES (1, '2011-09-17 12:02:49', 'Название новости', 'Описание новости', 'Ключевые слова', 'Текст новости ', 1);
# В поисковый индекс
F:\Zend\MySQL 5.1.52\bin>mysql -P9306
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 2.0.1-beta (r2792)

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> INSERT INTO `rt_news` (`id`, `date`, `title`, `descr`, `keywords`, `text`, `view`) VALUES (1, '1316250169', 'Название новости', 'Описание новости', 'Ключевые слова', 'Текст новости ', 1);
Query OK, 1 row affected (0.03 sec)

mysql>

Обратите внимание, что вставлять в индекс надо с указанием primary key, по умолчанию это поле id, также необходимо указывать название индекса куда вставляются данные.

Теперь в БД и индексе есть данные, можно с ними работать.

Извлечение данных из индекса

mysql> SELECT * FROM rt_news WHERE view=1\G;
*************************** 1. row ***************************
      id: 1
  weight: 1
    view: 1
    date: 1316250169
   title: Название новости
   descr: Описание новости
keywords: Ключевые слова
    text: Текст новости
1 row in set (0.00 sec)
# Параметр \G позволяет вывести данные вертикально

Изменение данных в БД и индексе

# Для БД
UPDATE `news` SET `title`='Name of news' WHERE  `id`=1 LIMIT 1;

 

# Для индекса
mysql> REPLACE INTO `rt_news` (`id`, `date`, `title`, `descr`, `keywords`, `text`, `view`) VALUES (1, '1316250169', 'Name of news', 'Описание новости'
, 'Ключевые слова', 'Текст новости ', 1);
Query OK, 1 row affected (0.03 sec)

# просмотр изменений для индекса
mysql> SELECT * FROM rt_news WHERE view=1\G;
*************************** 1. row ***************************
      id: 1
  weight: 1
    view: 1
    date: 1316250169
   title: Name of news
   descr: Описание новости
keywords: Ключевые слова
    text: Текст новости
1 row in set (0.00 sec)

Удаление данных из БД и индекса

# Для БД
DELETE FROM `news` WHERE  `id`=1 LIMIT 1;

 

# Для индекса
mysql> DELETE FROM `rt_news` WHERE  id=1;
Query OK, 0 rows affected (0.00 sec)

# просмотр данных из индекса
mysql> SELECT * FROM rt_news WHERE view=1\G;
Empty set (0.01 sec)

Заключение

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

Слышал мнение, что RT индексы сильно медленно работаю по сравнению с обычными индексами, но данная статья это опровергает.

Будут вопросы задавайте.

ЗЫ Еще один момент, все запросы которые относятся к БД я делал через обращение к mysql через порт 3306 (дефолтный), а запросы которые относятся к индексу через порт 9306, который указан в конфиге.

Статья просмотренна 486154 раз, зашло посетителей 42171

Спуск в Харьковские катакомбы

Август12

В компании в которой я работаю создается проект посвященный разным организациям нашего города и не только. И вот в рамках знакомства с организацией «Дети Подземелья» мы попросили провести небольшую экскурсию по «Харьковским катакомбам». Hазвать Харьковские катакомбы, катакомбами конечно трудно… это просто старые подвалы, какие-то лазы, но было интересно.

И так нас собралось 6 желающих для совершения «погружения» под землю. Мы встретились с Андреем Ковалевым, президентом этой организации на улице Рымарская 23.

Как нам рассказали, это старое здание постройки 19 века, и в то время под землей построили большой подвал для хранения угля и прочего провианта, сейчас часть этого подвала завалена обрушением стен и потолка, другие вполне сохранившиеся.
В 2006 году под землю провалился автобус с музыкантами, подробнее можно почитать тут.

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

В общем первый спуск мне понравился.

Освещения у меня было только с фонарика мобильного, поэтому фотки получили не очень:

Вид на Харьковску Филармонию

Вид на Харьковскую Филармонию

Вход катакомбы

Вход катакомбы

Вид с улицы в сами катакомбы, дырка использовалась для засыпания угля

Вид с улицы в сами катакомбы, дырка использовалась для засыпания угля

Главный зал. Тут есть колонная поддерживающая свод и соверменные канализации.

Главный зал. Тут есть колонная поддерживающая свод и соверменные канализации.

Это мы на перекрестке коридоов, осещаем рассказчика всеми фанарями.

Это мы на перекрестке коридоров, освещаем рассказчика всеми фанарями.

Высота земли над нами 3 метра, и даже тут есть корни и улитки! А там ведь тьма!

Высота земли над нами 3 метра, и даже тут есть корни и улитки! А там ведь тьма!

Улитка, местный житель

Улитка, местный житель

Вид на дырку для угля с катакомб

Вид на дырку для угля с катакомб

PS Вот еще коллега помогла найти статью Привидений в харьковских подземельях нет
PSS вот еще нашел

Статья просмотренна 469687 раз, зашло посетителей 35637

Мой первый jQuery плагин. Работа с размерами текста.

Август8

Фреймверк jQuery мне понравился с первых строк кода которые я на нём написал. Для одного проекта мне нужно было написать свой jQuery плагин для увеличения/уменьшения шрифта в статье, как и что делать я был не в курсе, помогли статьи на эту тему с разных источников.

Требования к jQuery плагину:
1 От начального значения шрифта текста уметь изменять высоту шрифта в заданом диапазоне и с заданым шагом.
2 запоминать измененное значение шрифта, дабы при следующем заходе на странице шрифт был выбранной ранее высоты.

Первый пункт подразумевает кол-во итераций в увеличение/уменьшение от основного значения, шаг — на какое число будет изменен начальный размер шрифта.
Пример, допустим изначальный размер шрифта равен 16px, если указать кол-во итераций равное 3-м, а шага 1, то это означает, что шрифт при увеличении будет изменяться 3 раза на 1 пиксель (17 18 19), при уменьшении будет иметь значения (15 14 13). Менять указанные переменные можно при настройке шрифта.

Для реализации второго пункта я привлек к работе возможность работы с куками, а именно плагин jquery.cookie.js, если данного плагина не будет, то основной палгин будет работать, но сохранять выбранный размер шрифта не сможет.

Ниже приведен тест самого плагина:

(function($) {
	/*
	 * значени по умолчанию
	 */ 
	var defaults = {
		iteration : 5,
		step : 1
	};
	
	/*
	 * глобальная переменная опций 
	 */
	var options;
	
	/*
	 * настройка кукисов 
	 */
	var cookieSettings = {
		expires: 7,
		path : '/',
		name : 'zoomtext'
	};
	
	/*
	 * Создаем объект с методами
	 */ 
	var methods = {
		
		/*
		 * Инициализация
		 */
		init:function(params) {

			var type, size;
			options = $.extend({}, defaults, params);

			if ($.cookie != undefined &amp;&amp; $.cookie(cookieSettings.name) != null )
			{
				if ($.cookie(cookieSettings.name) == $(this).css('font-size'))
				{
					type = options.type =  'px';
					size = options.defaultSize = $.cookie(cookieSettings.name).split(options.type).join('');
				}
				else
				{
					type = 'px';
					size = $.cookie(cookieSettings.name).split(type).join('');
					options.type =  'px';
					options.defaultSize = $(this).css('font-size').split(options.type).join('');
				}
			}
			else
			{
				type = options.type =  'px';
				size = options.defaultSize = $(this).css('font-size').split(options.type).join('');
			}

			$(this).css('font-size', size+type);			

			return $(this).data(cookieSettings.name) ? this : $(this).data(cookieSettings.name, true);
		},
		
		/*
		 * Увеличение шрифта
		 */
		inc:function() {
			
			var maxSize = parseInt(options.defaultSize)+options.iteration;
			var currentSize = parseInt($(this).css('font-size').split(options.type).join(''));

			if (currentSize &lt; maxSize)
			{
				var changedSize = (currentSize+options.step).toString()+options.type;
				$.cookie != undefined ? $.cookie(cookieSettings.name, changedSize, cookieSettings) : '';
				$(this).css('font-size', changedSize);
			}
		},

		/*
		 * Уменьшение шрифта
		 */
		dec:function() {
			
			var minSize = parseInt(options.defaultSize)-options.iteration;
			var currentSize = parseInt($(this).css('font-size').split(options.type).join(''));

			if (currentSize &gt; minSize)
			{
				var changedSize = (currentSize-options.step).toString()+options.type;
				$.cookie != undefined ? $.cookie(cookieSettings.name, changedSize, cookieSettings) : '';
				$(this).css('font-size', changedSize);
			}			
		},
		
		/*
		 * Сброс шрифта
		 */
		reset:function() {
			$.cookie != undefined ? $.cookie(cookieSettings.name, null, cookieSettings) : '';
			$(this).removeAttr('style');
		}
	};

	/*
	 *  магические методы для работы плагина
	 */
	$.fn.zoomtext = function(method){
		if (methods[method]) {
			// переброс на запрашиваемый метод + передача параметров метода
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || ! method) {
			// передача методу инициализации (init) параметров
			return methods.init.apply(this, arguments);
		} else {
			// просто инициализация, если что-то пошло не так
			return methods.init.apply(this);
		}
	};
})(jQuery);

В начале задаются дефольтные значения переменных (объекты) для работы:

	/*
	 * значени по умолчанию
	 */ 
	var defaults = {
		iteration : 5,
		step : 1
	};
	
	/*
	 * глобальная переменная опций 
	 */
	var options;
	
	/*
	 * настройка кукисов 
	 */
	var cookieSettings = {
		expires: 7,
		path : '/',
		name : 'zoomtext'
	};

в переменной defaults есть два ключа:
iteration, задает кол-во итераций в ту или другу сторону (описывал чуть выше в статье),
step, задает шаг шрифта, т.е. приращение к существующему.

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

Переменная cookieSettings необходима для работы с куками,
ключ expires задает кол-во дней жизни куки от начала её становки,
ключ path указывает на какую область сайта дейстует кука, в данном случае на весь сайт,
ключ name это название куки.

Для более полного описания параметров переменной cookieSettings лучше обратится к официальной документации

Далее я реализовал несколько методов для работы:
init — метод который определяет тукущий размер шрифта, применяет его к тексту с помощью инлайл-стилей (style=’font-size:размер_шрифта’) и сохраняет данные с помощью функции jQuery.data();

inc — метод который позволяет увеличить шрифт, если не превышен порог по увеличению (defaults.iteration), применяет к тексту и записывает данные в куку (если плагин кук подключен и работает);

dec — метод который позволяет уменьшить шрифт, если не превышен порог по уменьшению (defaults.iteration), применяет к тексту и записывает данные в куку (если плагин кук подключен и работает);

reset — позволяет сбросить шрифт к изначальному состоянию и убить куку.

Как видно из выше описанного ничего сложного тут нет, но где-же магия? Магия заключается в этих строках, повторное использование кода, цепочка вызовов:

	/*
	 *  магические методы для работы плагина
	 */
	$.fn.zoomtext = function(method){
		if (methods[method]) {
			// переброс на запрашиваемый метод + передача параметров метода
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || ! method) {
			// передача методу инициализации (init) параметров
			return methods.init.apply(this, arguments);
		} else {
			// просто инициализация, если что-то пошло не так
			return methods.init.apply(this);
		}
	};

Более подробно описано в статье jQuery для начинающих. Часть 7. Пишем плагины, на блоге Антона Шевчука, за что ему большое спасибо!

Как использовать этот плагин:

Подключаем jQuery, plugins

&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;http://blog.nagaychenko.com/jquery/plugins/jquery.cookie.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;http://blog.nagaychenko.com/jquery/plugins/jquery.zoomtext.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;

Необходимо создать управления, т.е. теги которые будут отвечать за увеличение/сброс/уменьшение шрифта, в моём случае я исользовал конструкцию ul-li

&lt;ul id=&quot;zoom&quot;&gt;
	&lt;li&gt;&lt;a href=&quot;#zoom&quot; id=&quot;increase&quot; title=&quot;увеличить шрифт&quot;&gt;increase&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;#zoom&quot; id=&quot;reset&quot; title=&quot;сбросить шрифт&quot;&gt;reset&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;#zoom&quot; id=&quot;decrease&quot; title=&quot;evtymibnm шрифт&quot;&gt;decrease&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p id=&quot;content&quot;&gt;некий текст&lt;/p&gt;

Вызываем плагин с нужными параметрами и создаем обработчики кликов на элементы управления

&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
	// вызов плагина с передачей необходимых значений
	$('p#content').zoomtext({step:1, iteration:2}); 

	// отслеживаем кликл для увеличения шрифта
	$('a#increase').unbind().bind('click',  function(){ 
		$('p#content').zoomtext('inc');
	});

	// отслеживаем кликл для сброса шрифта
	$('#reset').unbind().bind('click', function(){ 
		$('p#content').zoomtext('reset');
	});

	// отслеживаем кликл для уменьшения шрифта
	$('a#decrease').unbind().bind('click', function(){
		$('p#content').zoomtext('dec');
	});
});
&lt;/script&gt;

Теперь все это вместе на одной странице демо тут.

Текст который я использовал в статье был взят с сайта сонников, гороскопов, знаков зодиака. Здесь я всегда смотрю свой бесплатный гороскоп.

Буду рад услышать любые замечания и предложения через комментарии.

Статья просмотренна 469806 раз, зашло посетителей 35031

Изменение пути для хранения образа Android virtual device

Июнь28

Всем привет.

Я стал счастливым обладателем телефона под управлением ОС Android и мне очень заинтересовала возможность писать под эту ось разное ПО. Я установил себе плагин для Eclipse все настроил, накатал первый пример, создал виртуальное устройство Android virtual device (AVD) и хотел запустить свою первую прогу, но сразу наткнулся на костыли….

Оказывается, по-умолчанию образ устройства в Windows создается по пути нахождения папки пользователя, например у меня под 7-кой это такой путь: c:\Users\Максим\ и как видно моё имя в винде Максим, написанное кириллицей в кодировке винды (cp1251).

При создании образа устройства под Андроид, система его успешно создает в каталоге юзера, а именно c:\Users\Максим\.android\avd\name_of_vd\, также в папку на уровень выше от указанной, создается файлик name_of_vd.ini с содержанием:

target=android-7
path=c:\Users\Максим\.android\avd\name_of_vd.avd

но к сожалению (счастью) этот файлик в кодировке UTF-8, а мое имя юзера в кодировке сp1251 никак не равно имени в кодировке указанной в файле, отсюда и нет возможности запустить эмулятор (Под Linux таких проблем нет, т.к. там кодировка по-дефолту UTF-8). Что же делать, ну первым пришло на ум перенести мой образ на другой диск или папку с латинским названием, что я и сделал, но менеджер по созданию образов никак не хотел указывать на нужную мне папку. В Эклипсе никаких настроек я не нашел…, но Гугл мне дал ответ. Оказывается надо создать переменную окружения и туда занести путь для хранения образов. Как это делать показал на рисунках. Смотрите внимательно пути и выделенные пункты окон.

Пуск-Панель управленя-Система

Пуск-Панель управленя-Система

Жмем кнопку "Переменные среды"

Жмем кнопку «Переменные среды»

Создаем сисстемную переменную

Создаем сисстемную переменную

Заполняем поля

Заполняем поля (путь можете менять на свой)

Не забываем перегрузить эклипс и перенести свои образы немного изменив .ini файл или создаем их заново уже в новой директории.

В помощь новичкам!

Статья просмотренна 158017 раз, зашло посетителей 19278

Платим меньше за электроэнергию. Установка тарификационного счетчика

Май17

электричествоВсе платят за потребленную электроэнергию и все наверняка заметили, что дважды в 2011 повышались тарифы на онную, документ НКРЕ від 10.03.1999 р. № 309, у кого есть проблемы с переводом текста используйте переводчик. Я, как и любой нормальный человек, хочу сэкономить на её потреблении, замена ламп накаливания на энергосберигающие дало своё преимущество, но хочется большего.

На сайте Харьков ОблЭнерго приведены текущие тарифы на потребляемую энергию, также в примечаниях есть ссылка на документ «НКРЕ від 10.03.1999 р. № 309» в котором описывается, что есть также несколько тарифов в том числе и ночной, который ниже чем дневной. Вот на нём и попытаюсь сэкономить.

Есть дома приборы, которые я не могу заменить, но которые я могу включать ночью, в то время когда тариф ниже, у меня к ним относятся:
стиралка, есть таймер отсрочки стирки, как раз можно поставить вечером и запрограммировать на стирку в ночь
хлебопечка, аналогично, поставить все с вечера и утром проснуться от запаха новоиспеченного хлеба))
посудомойка, таймер — наш спаситель
духовой шкаф, вот с ним не так все гладко, есть вещи которые надо контролировать и не будешь же готовить еду ночью, но есть вещи которые можно и ставить на ночь — запечь утку, курица, мясо. Электрический шкаф намного лучше управляем, чем газовый, поэтому в плане безопасности я не волнуюсь.
бойлер на 100л, хоть и не имеет таймера, но есть таймеры продающиеся отдельно цена в районе 100грн, вот и будет он греть воду в ночное время. По моим экспериментам мой бойлер держит горячую воду 3-е суток, так что остыть не успеет, при нормальном потреблении
— также по своим биологическим свойствам я ложусь в 00 или 1 час ночи, также и жена, следовательно и ТВ который мы смотрим в это время платить за его энергию будем меньше.

Подумав, подсчитав мы решили перейти на двух тарифный счетчик. Расчет энергии будет такой
с 7 утра до 23 вечера расчет за потреблени будет такой же как и однотарифного счетчика, т.е. 100%, а вот с 23 до 7 будем платить по коэффициенту 0.7, т.е. 70% от потребленной энергии. 3-х тарифный счетчик имеет следующие тарифы (переписал с сайта Харьков Облэнерго):
«1,5 тарифу в години максимального навантаження енергосистеми (з 8-ї години до 11-ї години і з 20-ї години до 22-ї години);
повний тариф у навпівпіковий період (з 7-ї години до 8-ї години, з 11-ї години до 20-ї години, з 22 до 23 години);
0,4 тарифу в години нічного мінімального навантаження енергосистеми (з 23 години до 7 години).
«, этот тариф выгоден тем, кто отапливает свои жилища электричеством.

Теперь расскажу с чего начать и какие есть трудности, все дело происходит в г.Харьков, Украина.

17.05.2011

Идем в эту организацию по адресу г.Харьков, ул.Плехановская,126/2 далее в комнату 103, в ней проихсодит программирования счетчиков, там напишут на бумажке какие счетчики они программируют и какой надо купить, мне написали два:
Энергомера CE 102 S6 145 OKV и Меркурий 200.02 второй счетчик датой выпуска после марта 2010 года. По приведеным ссылкам я позвонил, узнал о цене, мне понравился Меркурий (он более компактный и стоимость чуть меньше чем у первого) за него я заплатил 366 грн.
После покупки счетчиков идем обратно в организацию, ищем окошко с названием своего района проживания и просим у них бланк заявления, далее тебе говорят внутренний номер телефона РОЭ своего района, идет к охране и звоним по этому номеру, говорим по какому делу беспокоят. За тобой выходят, готовим паспорт (права) и регистрируемся у охраны, получая разовый пропуск. Поднимаеся в кабинет в который ведут, пишем заяву, в которой указываем адрес замены, тип зоны, название счетчика и его заводской номер. После, работник организации идет к начальнику и тот подписывает заяву, далее идем в кабинет 103, отдаем заяву, счетчик и регистрируемся в журнале. В этом кабинете происходит программирование счетчика по указанному вами тарифу. На этом пока все, сказали перезвонить 23 мая 2011 и узнать готов ли счетчик. Замечу, программирование для население БЕСПЛАТНОЕ!

Мне было инетерсно сколько я должен буду заплатить за замену, пошел в окошко своего района узнать, спросили какого года выпуска счетчик который надо демонтировать, у меня ему года 2-3. Сказали в таком случае замена будет втоить 26 грн, более точно узнаю когда получу официальные квитанции. Продолжение следует.

23.05.2011

Я позвонил в службу программирования счетчиков и мне подтвердили, что счетчик готов и можете подъезжать.

25.05.2011

Я подъехал, забрал счетчики, заявку, расписался в журнале и пошел в окошко оплаты, сказал, что мне запрограммировали счетчик и что мне дальше, девушка-кассир проверила моё состояние оплаты и дала бумагу об оплает.

квитанция на замену счетчика

квитанция на замену счетчика

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

Всем удачи!

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

Юзер1 — экономия за год составила 108,71 грн по тарифам на 01,04,2011

06.11 07.11 08.11 09.11 10.11 11.11 12.11 01.12 02.12 03.12 04.12 05.12 06.12 ИТОГО
Iт, кВт 130 208 159 172 193 190 168 202 168 197 201 231 180 2399
IIт, кВт 40 71 79 40 47 52 55 63 48 49 44 68 57 713
итого, кВт 170 279 238 212 240 242 223 265 216 246 245 299 237 3112
итого, грн 49,33 89,09 74,13 64,65 74,86 75,59 68,66 83,98 66,11 77,05 76,69 96,39 73,77 970,30
Полный
тариф, кВт
187 309 272 229 260 264 247 292 237 260 264 328 261 3410
итого, грн 55,53 100,03 86,54 70,85 82,16 83,62 77,42 93,83 73,77 82,16 83,62 106,96 82,52 1079,01

Юзер2 — экономия за год составила 383,77 грн по тарифам на 01,04,2011

06.11 07.11 08.11 09.11 10.11 11.11 12.11 01.12 02.12 03.12 04.12 05.12 06.12 ИТОГО
Iт, кВт 221 259 229 268 270 286 250 316 250 283 260 305 276 3473
IIт, кВт 193 212 180 225 197 143 150 146 150 130 200 303 227 2456
итого, кВт 414 471 409 493 467 429 400 462 400 413 460 608 503 5929
итого, грн 138,34 159,13 136,51 167,16 157,67 143,81 133,23 155,85 133,23 137,97 155,12 209,11 170,80 1997,93
Полный
тариф, кВт
497 562 486 589 551 490 464 525 464 469 546 738 600 6981
итого, грн 168,62 192,33 164,6 202,18 188,31 166,06 156,58 178,83 156,58 158,4 186,49 256,53 206,19 2381,7

Юзер3 — экономия за 10 месяцев составила 102,46 грн по тарифам на 01,04,2011

09.11 10.11 11.11 12.11 01.12 02.12 03.12 04.12 05.12 06.12 ИТОГО
Iт, кВт 254 397 641 211 727 144 335 91 144 256 3200
IIт, кВт 39 79 70 99 106 103 82 12 27 43 660
итого, кВт 293 476 711 310 833 247 417 103 171 299 3860
итого, грн 94,20 160,95 246,68 100,40 291,19 77,42 139,43 28,86 49,69 96,39 1285,21
Полный
тариф, кВт
310 510 741 352 878 291 452 108 183 317 4232
итого, грн 100,40 173,36 257,63 115,72 307,61 93,47 152,20 30,26 54,07 102,95 1387,67

Как видно, и логично, чем больше потребляешь, тем быстрее окупаешь.

Статья просмотренна 151129 раз, зашло посетителей 24479

Особенности работы LAST_INSERT_ID() и AUTO_INCREMENT в MySQL

Март11

Всем привет.

Причина по которому я написал эту статью — это неожиданное поведение ф-ции LAST_INSERT_ID() при выполнении запроса в котором я в поле с атрибутом AUTO_INCREMENT передавал значение.

LAST_INSERT_ID()

И так имеем таблички

Таблица авторов:

CREATE TABLE `author` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	`fam` VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	`birthday` DATE NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=1;

Таблица книг авторов:

CREATE TABLE `books` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`id_author` INT(10) NULL DEFAULT NULL,
	`book` VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	PRIMARY KEY (`id`),
	INDEX `id_author` (`id_author`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=1;

Добавляем данные, обратите внимание на запросы тут :

INSERT INTO `author` (`id`, `name`, `fam`, `birthday`) VALUES (NULL, 'Николай Николаевич', 'Носов', '2008-11-23');
SET @lastID := LAST_INSERT_ID();
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (NULL, @lastID, 'Незнайка учится');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (NULL, @lastID, 'Незнайка-путешественник');

и тут :

INSERT INTO `author` (`id`, `name`, `fam`, `birthday`) VALUES (5, 'Артур Конан', 'Дойль', '1859-05-22');
SET @lastID := LAST_INSERT_ID();
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (NULL, @lastID, 'Затерянный мир');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (NULL, @lastID, 'Шерлок Холмс');

Ну разница не только в значениях полей, а тут главная фишка, что при добавлении автора в первой тройке запросов, автоинкремент делал сама БД, а во второй тройке я принудительно указал номер в поле автоикремент, вот что получилось:

mysql> SELECT * FROM author;
+----+-------------------------------------+------------+------------+
| id | name                                | fam        | birthday   |
+----+-------------------------------------+------------+------------+
|  1 | Николай Николаевич               | Носов     | 2008-11-23 |
|  5 | Артур Конан                           | Дойль     | 1859-05-22 |
+----+-------------------------------------+------------+------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM books;
+----+-----------+-----------------------------------------------+
| id | id_author | book                                          |
+----+-----------+-----------------------------------------------+
|  1 |         1 | Незнайка учится                 |
|  2 |         1 | Незнайка-путешественник |
|  3 |         2 | Затерянный мир                   |
|  4 |         2 | Шерлок Холмс                       |
+----+-----------+-----------------------------------------------+
4 rows in set (0.00 sec)

Как вы заметили, с таблицей авторов все окей, 1 и 5 запись добавились с теми номерами ключей которые указала БД и я соот.
Во второй таблице — книги, все хуже. У книг с ИД 1 и 2 ИД_автора все ок, привязаны к автору с ИД1 в таблице авторов, а вот книги с ИД 3 и 4 привязаны к автору ИД которого в таблице авторов просто нет?!

Почему произошла такая ситуация. Разбираем.

Оказывается эта функция LAST_INSERT_ID() возвращает ИД поля с атрибутом автоинкремент если запись была вставлена успешно и автоинкремент работал!!!! Что у нас и было в первой тройке запросов, а вот во второй тройке запросов увы такого не было, т.к. я указал ИД, а значение 2 взялось, т.к. последний успешный запрос был при добавлении второй книги первого автора!

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

Вот пример

TRUNCATE `author`;
TRUNCATE `books`;
INSERT INTO `author` (`id`, `name`, `fam`, `birthday`) VALUES (NULL, 'Артур Конан', 'Дойль', '1859-05-22');
SET @lastID := LAST_INSERT_ID();
INSERT INTO `books` (`id`, `id_author`, `book`) 
VALUES (NULL, @lastID, 'Затерянный мир'),
(NULL, @lastID, 'Шерлок Холмс');

Результат

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)

А если сделать так

TRUNCATE `author`;
TRUNCATE `books`;
INSERT INTO `author` (`id`, `name`, `fam`, `birthday`) VALUES (NULL, 'Артур Конан', 'Дойль', '1859-05-22');
SET @lastID := LAST_INSERT_ID();
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (NULL, @lastID, 'Затерянный мир');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (NULL, @lastID, 'Шерлок Холмс');
SELECT LAST_INSERT_ID();

Результат

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

Век живи — век учись (© Народная мудрость).

В заключении еще решил разобрать поведение атрибута AUTO_INCREMENT.

AUTO_INCREMENT

Это такой атрибут который генерирует порядковый номер к указанному полю. Полей должно быть только с типом integer или float (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, FLOAT) и имеющий индекс типа (UNIQUE, PRIMARY, KEY). Причем у каждого из типа поля есть свой предел автоинкремента, например для поля TINYINT это значение 127 или 255 для TINYINT UNSIGNED и тд смотрите документацию. Каждая последующая запись будет +1 (по-дефолту) к максимальному числу до добавления в этом поле, наверное не так лучше сказать.
В MySQL есть вспомогательная БД information_schema в которой хранится необходимая информация о всех таблицах всех БД сервера. И вот именно там храниться следующий номер для автоинкремента, т.е. перед добавление записи в таблицу БД не ищет максимальный номер записи, на это ведь будет тратиться время, которое дорого.
В таблице может быть только одно поле которое имеет автоинкремент, и причем это поле не должно иметь дефолтного значения.
Если мы хотим указать какой-то свой номер для поля с автоинкрементом, то мы должны просто передать этому полю значение. Если значение уже есть в таблице, то будет ошибка если тип индекса в поле UNIQUE или PRIMARY, но есть тип индекса KEY то запись спокойно добавится.
Если по каким-то причинам нам надо указывать поле с автоинкрементом в запросе, но мы хотим чтобы этому полю было присвоено значение автоинкремента автоматом, то в это поле надо передать 0 (ноль) или NULL:

INSERT INTO`tablename`VALUE (0);
или
INSERT INTO`tablename`VALUE (NULL);
или
INSERT INTO`tablename`VALUE (NULL), (0); // два запроса на добавления

Если по каким-то причинам вы хотите добавить значение 0 в поля автоинкремента, для этого необходимо прописать в файле-настроке (my.ini / my.cnf) следующую строчку

sql-mode = NO_AUTO_VALUE_ON_ZERO

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

Если по каким-то причинам вам необходимо сделать чтобы следующая запись начиналась с какого-нибудь друго числа, просто напишите команду:

ALTER TABLE `tablename` AUTO_INCREMENT = тут_пишем_нужное_число;

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

А например возникла задача делать автоинкремент не ++1 а через 5, т.е. 1,6,11 т.д. как быть в таком?
Для этого имеются две переменные auto_increment_increment и auto_increment_offset. auto_increment_increment — указывает шаг приращения, а auto_increment_offset указывает стартовую точку.
Для просмотра что у вас используется команда, которая показывает как у вас настроен автоинкремент:

mysql> SHOW VARIABLES LIKE 'auto_inc%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 1     |
| auto_increment_offset    | 1     |
+--------------------------+-------+
2 rows in set (0.00 sec)

Поменять можно 2 путями — только на время работы сервера БД (до перезагрузки) и навсегда — смена конфигурационного файла

1 путь : 
SET @@auto_increment_increment=5; SET @@auto_increment_offset=1;

2 путь в файле my.ini / my.cnf пишем строки :
auto_increment_increment=5; 
auto_increment_offset=1;

Более детальней об изменении AUTO_INCREMENT читать тут.

Обнаружил в интернете интересный сайт с подкастами. Советую скачать podcast, подкасты на различные темы.Также советую послушать подкасты на сайте dev.mysql.com по тематике данной статьи.

Статья просмотренна 195546 раз, зашло посетителей 54601

Кеширование запросов DESCRIBE при работе с моделями в Zend Framework

Март5

Добрый всем день!

Если вы пишите свой сайты с использованием ZendFramework и при этом используете модели для работы с БД, то вы должны знать, что сам фреймворк первым запросом будет получать информации о таблицы с которой работает:

DESCRIBE `table_name`;

следовательно каждый раз фреймворк делает чтение её структуры, что приводит к лишнему запросу и когда таблиц много или посетителей ресурса — тормозам.

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

Я создал абстрактный класс от которого должны наследоваться все мои модели, назвал его AbstractTableModel, вот его код:

<?php
/**
 * Class fot caching describe table query
 *
 * @filesource
 * @author maxnag
 */
abstract class AbstractTableModel extends Zend_Db_Table_Abstract
{
	public function __construct($config = array())
	{
		parent::__construct($config);
		
		if (Zend_Db_Table_Abstract::getDefaultMetadataCache() === null)
		{
			$frontendOptions = array('automatic_serialization' => true);

			$zendCacheDir = './cache/'; // directory for caching

			if (!file_exists($zendCacheDir))
			{
				mkdir($zendCacheDir, 0777);
			}

			$backendOptions  = array('cache_dir' => $zendCacheDir);

			$cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
			Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
		}
	}
}

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

Удачи, Максим.

Статья просмотренна 77499 раз, зашло посетителей 11670

Новый хостинг. Новая флешка в подарок!

Февраль28

сама флешка-подарокЭта статья не несёт в себе рекламный характер, цель её просто радость)).

Дело было в начале 2011 года, у меня закончился контракт с одним из хостеров, на котором я имел довольно старый пакет с пространством всего в 250 MB и устаревшими версиями ПО. Анализ конкурентов показал мне новый хостинг с быстрым каналом, с неограниченными кол-вами БД, поддоменов и тд. И я нашел, характеристики мне понравились, я взял тариф ПАКЕТ «Максимум» и в этот момент на этом и других тарифных планах была акция. Я выполнил условия акции (оплата хостинга на год). И начал ждать когда ко мне придет долгожданный подарок.

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

17.02.2011 Пишу повторное письмо, отвечают, говорят что почтой заказным письмом выслали на указанный мною адрес. Жду.

конверт с флешкой28.02.2011 Приходит с почты извещение. Иду на почту и наконец получаю обещанная флешка в подарок. Приятно.

Единственно мне непонятно почему за свой подарок я должен бороться?! А если бы я не был настойчивым, подарок так бы и не пришел. Отсюда мораль — всегда боритесь за свою жизнь, если даже обещают халяву.

Максим.

ЗЫ Извиняюсь за качество фоток, фоткал на телефон

Статья просмотренна 70522 раз, зашло посетителей 10348

 « предыдущие статьи 

Облако тегов

cli csv dump events form Kohana locale models MySQL mysqldump orm PHP tools trigger validate газ газовый счетчик итоги кеширование переменные

Облако тегов плагина WP Cumulus для WordPress требует для просмотра Flash Player 9 или выше.

Я на твиттере!

  • у твиттера тоже бывают перерывы...

Календарь

Январь 2018
Пн Вт Ср Чт Пт Сб Вс
« Июл    
1234567
891011121314
15161718192021
22232425262728
293031  

Сейчас на сайте