28 февраля 2006

Быстрая загрузка CSV-файла в базу данных

Как известно, для работы с CSV-Файлами PHP предоставляет функции fgetcsv и fputcsv. Поскольку эти функции обрабатывают файл построчно, то загрузка данных в базу данных происходит очень медленно: я так ни разу и не дождался, когда же обработается тестовый файл 40 метров длиной.

Опрос показал, что есть специальные средства, позволяющие загрузить CSV в базу очень быстро - речь шла о софтине bcp из комплекта MS SQL. Но тулза эта виндовая, а мне требовалось решение на кросс-платформе.

Так я обнаружл в MySQL'е наличие мега-структуры LOAD DATA IN FILE. Работает ну очень быстро: мой преславутый файл в 40 метров загружается за 16 секунд. В этом SQL-запросе есть всё, что надо для работы с CSV: указание символов для экранирования и отквочивания, пропуск первых N строк (заголовок), итд.

Кому лень ковырять мануал, милости прошу поюзать специально мной написанный для этой цели PHP-класс.

27 февраля 2006

Про простоту и незамысловатость

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

Но когда я вижу вот такой код, то я готов завести ещё 5 блогов и писать ещё более простые вещи ещё более примитивным языком:

<?php
$idmode = $userdata->user_idmode;
if ($idmode == 'nickname')
  $user_identity = $userdata->user_nickname;
if ($idmode == 'login')
  $user_identity = $userdata->user_login;
if ($idmode == 'firstname')
  $user_identity = $userdata->user_firstname;
if ($idmode == 'lastname')
  $user_identity = $userdata->user_lastname;
if ($idmode == 'namefl')
  $user_identity = $userdata->user_firstname.
  ' '.$userdata->user_lastname;
if ($idmode == 'namelf')
  $user_identity = $userdata->user_lastname.
  ' '.$userdata->user_firstname;
if (!$idmode)
  $user_identity = $userdata->user_nickname;
?>

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

Как бы я написал? Просто: switch() и в дефолте $user_identity = $userdata->user_nickname;

Кстати, знаете, как я понимаю, что написанный код действительно хорош? Когда после N-ной правки я удаляю половину кода, а функциональность не теряется и не ухудшается. Чаще всего так получается сделать, если сделегировать часть работы какой-то другой и более грамотно написанной программе: броузеру, апачу, май-эс-кью-элю, самой операционке... И тогда я слышу чей-то шепот за спиной: keep it simple, stupid :]

Урок чернухи

ON DUPLICATE KEY UPDATE ещё круче

Я уже писал, как можно заменить связку из трёх запросов SELECT-INSERT-UPDATE на один запрос INSERT-SELECT FROM-ON DUPLICATE KEY UPDATE. Так же я тогда отметил о таком не очень удобном моменте, как необходимость нагенеривать данные для запроса: как для INSERT-блока, так и для UPDATE-блока. Например, в данный момент я ковыряю кусок кода, который либо добавляет нового подписчика, либо обновляет данные существующего:
<?
$sql = "INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES ('".$email."',".$language.",".$currency.")
ON DUPLICATE KEY UPDATE
`id_language`=".$language.",
`id_currency`=".$currency;
?>

Видите? Бедному РНР нужно подставить значения переменных не только в INSERT, но и в UPDATE. Чем это плохо? Во-первых, если придётся ковырять этот код в следующий раз, например, перед значениями $language и $currency приписать (int), чтобы явно привести их к целому типу, то придётся сделать 4 правки. Во-вторых, работы для PHP-сервера больше: одно дело просто строчку скопировать, другое - проставлять значения переменных. Столбцов может быть не 2-3, а 20, да плюс несколько таких запросов (в цикле) - тогда это может быть значительно.

Чтобы в этой ситуации облегчить работу PHP-серверу и немного больше напрячь ленивый SQL-сервер, есть функция VALUES(). Она позволяет, в данном случае, обратиться в UPDATE-блоке к данным из INSERT-блока. Таким образом, код становится чище:
<?
$sql = "INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES ('".$email."',".$language.",".$currency.")
ON DUPLICATE KEY UPDATE
`id_language`=VALUES(`id_language`),
`id_currency`=VALUES(`id_currency`)";
?>

26 февраля 2006

Скорочтение

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

Меня долго смущала практическая реализизация такого требования: где найти много текста разной ширины. Я сразу откинул идею скачивания с lib.ru разных книжек и переформатирования их в броузере или ворде - читать с экрана не люблю, только по необходимости.

И вот сегодня меня осенило! Я читаю блоги в Абилоне, и одна из вертикальных колонок в его окне служит для отображения текста конкретного заголовка: разумеется, ширина этой колонки регулируется, таким образом обеспечивая удобный интерфейс для 1) моего обучения и 2) чтения новостей. Всё равно такую информацию я на бумаге не читаю...

Таким образом, я получаю выгоду от чтения интересных новостей :]

24 февраля 2006

Миранда-броузер

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

  1. я пишу адрес (УРЛ) в броузере. В настройках броузера прокси-сервер прописан как локальный адрес, который на самом деле представляет собой плагин к миранде, благо она предоставляет интерфейс для плагинов. Таким образом адрес попадает в аську;
  2. плагин в миранде коннектится к серверу ICQ через бесплатный местный прокси-сервер и после этого остылает принятый УРЛ на определённый ICQ-номер (задаётся в настройках). Таким образом адрес попадает на другой номер;
  3. другой номер - это мой PHP-скрипт на удалённом серваке, который крутится в цикле и принимает входящие ICQ-сообщения (типа демон);
  4. получив адрес, PHP-скрипт делает читает весь контент по этому адресу и возвращает его обратно по цепочке в мой броузер.

Схема работыДумаю, схема будет работать даже для всяких имеющихся на странице картинок, скриптов и цсс-файлов.

На данный момент меня смущает только пункт 1: не знаю, как это грамотно сделать, всё руки не доходят попробовать...

Тырить инет - очень по-русски, но меня интересует только техническая сторона :]

23 февраля 2006

Punto Switcher для программиста

Оказывается, люди очень похожи - уже в который раз я слышу от разных товарищей то же, что раньше говорил сам: Punto Switcher (далее ПС) неудобен, потому что лезет исправлять то, что не нужно. Ну что ж, так и есть, если он работает в автоматическом режиме. Я подумал, что неплохо будет поделиться своим опытом, потому что ПС - удобный молоток для забивания сразу нескольких гвоздей.

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


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

  • Break - конвертировать раскладку (если вы набрали "cfif", то это тут же по нажатии Break превратиться в "саша"). Отлично работает для только что набранного слова;
  • Shift+Break - конвертировать раскладку для всего выделенного куска текста.
  • Alt+Break - инверсия регистра (было "Саша", выделяем, нажимаем, становится "сАША");
  • Alt+ScrollLock - перевод в транслит: соответственно, только из русского в английский (было "Саша", выделяем, нажимаем, становится "Sasha"). Из-за включённого таким образом ScrollLock может неожиданно странно начать себя вести скроллинг с клавиатуры в Excel, но это поправимо - выключите его и всё (ScrollLock, не Excel :] ).
Это раз.

Есть такая удобная штука, как автозамена. Сие означает, что набор всех часто набираемых комбинаций текста можно упростить. Какой текст программиста чаще всего набирает? Вот мои примеры:
  • for($i=0; $i>sizeof($data); $i++)

  • while(list($key, $val) = each($attributes))

  • not_empty_array()

  • $attributes[""]

  • border: 1px solid blue;

  • document.getElementById('')

  • ну иногда ещё своё имя или фамилия в письмах

Всё это я получаю, набрав первые 2-3 буквы, после чего загорается виндосовский хинт, сигнализирующий о том, что если я нажму пробел, мой текст будет автоматически заменён.

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

Хинт: не надо набивать в поле "Заменять что" нормальных слов типа "for" или "while" - это чревато тем, что вы будете материться, когда в письме напишете это слово, затем нажмёте естесственный пробел, а этот "глупый ПС" сделает замену! Лучше использовать "fo" и "whil".

Это два.

И теперь три: на закуску супер-мега тул. Называется "история буфера обмена", выглядит обычным поп-ап меню так:

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

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

Как настроить.

  1. Идём в Параметры -> Общий и включаем галку "Разрешить слежение за буфером обмена".
  2. Шагаем в Параметры -> Горячие клавиши, там выбираем пункт "Показать историю буфера обмена", и выставляем шоткат (у меня это англ. буква H + клавиша Win).

В ПС есть ещё несколько функций, но ими не пользуюсь. Если кто научит - спасибо скажу.

Всех с праздником!

22 февраля 2006

Быстрая проверка на ненулёвость

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


if($id_product * $id_boutique * $id_top > 0)


Примерно так же можно проверить, является ли хоть одна из проверяемых строк непустой:


if($name_product . $name_boutique . $name_top != "")

21 февраля 2006

Ругаться нет сил

Полчаса дебажил, чтобы обнаружить, что я написал не "enabled", а "ebabled".

20 февраля 2006

JSMin

JSMin - это маленькая консольная прожка (33 Кб), которая получает на вход код JavaScript, а на выходе выдаёт код JavaScript с выкушенными комментами и переносами строк. Код остаётся работоспособен и не принимает вид одной строки - я так думаю, потому, что в JavaScript концом оператора может считаться как точка с запятой, так и конец строки, а в последнем случае слепить две строки означает нарушить работоспособность программы. Так что ваш код принимает просто менее документированный вид, типа продакшн-сурс.

Как пускать. Внимательный читатель, думаю, заметил, что я написал "получает на вход код JavaScript" - сие означает, что надо передать параметром не имя файла, а его текст. В простейшем случае - запустить jsmin.exe и набить всё вручную в консоли. Но мы же украинские девелоперы! Да здравствует автоматизация!

Такой командой мы передаём этому выкусывателю текст входного файла, и указываем, куда сложить вывод:


jsmin.exe < in.js > out.js


В среднем файл сжимается на 40-50%.

Автор проги, похоже, читал увещевания Джоэля Спольски про поддержку юникода, так что доступные кодировки - ASCII и UTF-8.

Кстати, приятный work-around: таким образом можно "жать" все файлы с Си-подобным синтаксисом: не только JavaScript и Си, но и РНР, и даже CSS.

Скачать оригинальный JSMin.exe, JSMin, написанный на С,
на РНР или на Си-решётке