век живи - век учись...
Oct. 24th, 2013 10:23 amПришло время обломов и озарений.
Как я однажды уже упоминал, занялся переносом роботов с одного сервера на другой. Всё бы ничего, но на первом сервере S1 база интербейзовая, а на втором - mysql. Что, в общем-то, не проблема. Но на S1 - трастикс (старенький), а на S2 - убунта. На S1 - koi8-r дефаултом и база win1251, а на S2 - utf8.
Впрочем, ну на уникод я переползаю намеренно. Но такая разница подсовывает грабли регулярно.
Недавно писал о том, как боролся с уникодом на связке perl/apache/mysql. Хотя казалось бы раз на убунте уникод нативен, то и тут никаких заморочек быть не должно. То есть я ожидал, что везде дефаулты будут выставлены так как надо. Да хрен там.
Новая история.
На новом сервере всё начиналось с базы статистики. Т.с. с её новой реинкарнации.
Она потихоньку росла и перестала быть исключительно базой статистики.
Дошло дело до переноса базы нарядов.
Небольшая реорганизация базы, конечно, случилась, хотя относительно некоторых нововведений не уверен что решение было верным. Впрочем, переделать никогда не поздно, тем более, что до эксплуатации ещё далеко. Но как и на старом сервере база нарядов отдельна сама по себе. Хотя некоторые сущности могут перескаться. Движёк myisam-овский, если что.
Следующая база - температурная. Робот обходит датчики, сидящие на телефонных линиях, меряет сопротивление и вычисляет температуру на абонентских ступенях. На старом сервере база была сама по себе. На новом как? Генерить ещё одну базу что-то не хочется. Напрашивается создание её таблиц в одной базе с другими таблицами.
И тут как раз и напрашиваются изменения. Первая база со статистикой содержит не только статистику но и разную конфигурацию. Другим задачам тоже может потребоваться конфигурация. И что новую базу создавать, которая будет дублировать уже имеющиеся таблицы в базе статистики?
Поэтому было решено глобализовать базу статистики и перетащить в неё таблицы из базы нарядов.
Первая половина задачи получилась только с третьей попытки. Ибо rename database не нашлось, а смухлевать тупо копируя таблицы на уровне файловой системы. Да, да, копировать БД файлами может выйти боком, но в некоторых случаях это вполне приемлемый способ, если обеспечить нужные условия неприкосновенности БД на время копирования. Обеспечить-то я мог, но в старой базе ещё и функции с процедурам сидят. Я о них забыл. :) Можно было сделать mysqldump --no-data -R и выдернуть нужные определения, но где-то ещё случились глюки и какие-то таблицы тормозили. Я подумал что с индексом что-то и откатился на старые базы. На следующий день робот меня известил что несколько таблиц вообще порепались, но к тому времени я уже решил, что делать буду как положено, хоть и медленно - через бекап дампа.
Так получилась общая БД по станции, в которой будет жить всё что к ней имеет отношение. С интербейзом такое объединение было бы под вопросом. Потому что это один большой файл. Ну или несколько. Когда он становится толстым-толстым, то его и бекапить утомительно, и прочие пробемы возникают. С myisam проще - каждая таблица сама по себе. В общем, пока всё ОК и непредвиденных нежелательных последствий всё ещё не предвидится. ;)
В базе нарядов процедур не было, поэтому она перенеслась "на ура". Не помню даже - кажется копированием на уровне файловой системы перенёс. Проблем не было - поэтому и не помню.
И вот дело дошло до температуры.
Создал пару таблиц, написал скрип. Скопировал справочник скриптом. А с таблицей текущей температуры застрял.
Есть исходная таблица, есть целевая. В первой есть данные, во второй пусто. Скрипт данные из первой вынимает, во вторую складывает. Пытается складывать. То есть $db->do($stmt) проходит без ошибок, но данных в целевой таблице нет! Для простоты стейтмент содержит плоский текст. Запускаю phpmyadmin, скармливаю запрос и оп-па! Данные в таблице! Что за чертовщина? Дальше следует ещё куча танцев с бубном. Безрезультатно. То есть вот этот самый скрипт, в котором изменил только запрос недавно перенёс справочник, а температуру переносить не хочет. Родился этот скрипт из того, что переносит данные из старой базы нарядов в новую. По несколько тысяч. И не кашлянёт. А температуру не хочет.
Запускаю на первом сервере mysql и задают тот же самый запрос. Оба-на! Данные оказались на месте! То есть засада и не в базе, и не в дровах, а где-то в перле. Про незакрытую транзакцию и откат я думал, но исходные скрипты с транзакциями не работают. С транзакциями не работают, но работают, прости Господи. ;)
Кажется пытался оформить через транзакции, но меня послали. Плохо помню.
Но вот решил в соответствии с правилом "измени хоть что-нибудь" туглануть AutoCommit. О чудо! Данные оказались в таблице. Ничего не понял. В нарядах и справочнике всё работало так, а тут потребовалось иначе. Не стал заниматься разгадыванием загадки и на радостях допилил скрипт, чтобы тот обновлял данные.
Вчера занимался допиливанием веб-интерфейса.
Есть задача: нужно отобразить сегодняшние наряды. А за сутки может прийти нарядов очень много. Несколько тысяч. Выводить их все глупо. Можно выводить по страницам, но я придумал, разбивать их по группам. Например, сначала по типам услуг (дебиторка, доп.услуги, разграничением доступа). Потом, если их всё ещё дофига, то сгрупировать по времени. По часам хотя бы. Но и за час можно получить до двух тысяч. Тоже дофига. Значит нужно сгруппировать ещё более подробно, и только когда записей окажется немного, их можно выводить.
А в базе уже за два миллиона записей и группировка идёт медленно. Секунд 10 и повторный запрос ничерта не ускоряет. Стал RTFMить и пошёл юстировать параметры сервера. Добавил памяти для индексов. Пробегая по переменным удивился проблемам с InnoDB. То если удивился не проблемам, а тому что кто-то его использует. Обежал базы и обнаружил несколько с этим энджином. Медиавики, оказалось, не напрягалась относительно него. Конвертнул все что нашёл.
И вот тут-то меня и ждал сюрприз: температурная таблица создана инодбшной, ба-али-ин. Ага. А myisam транзакции не поддерживает. Собственно поэтому всё кроме температурки нормально работало, а температурка не работала потому что транзакции откатывались. Эксперимент-то я ещё проведу, чтобы убедиться.
Хотя надо всё-таки переключить сервак на дефаултовый myisam, а то уже в который раз конверченьем занимаюсь, когда забываю явно энджин указать.
А может не надо? Чтобы приучить себя всё-таки явно указывать энджин? ;)
Ах, да! Запрос быстрее работать не стал.
Тут бы explain-уть это дело. Интересно можно ли мускулю принудительно указать план как интербейзе....
Но не приучил себя к нему (по каждому чиху). :)
Собственно, закавыка тут в том, что есть поле времени (timestamp) вставки записи и исполнения наряда. Уникальных первых полтораста тысяч, а вторых - чуть больше мильёна. Каждое поле индексировано.
А "сегодняшняя" запись означает что исполнена сегодня или вставлена сегодня. И вот "INSERT_TIME>=CURDATE() OR EXEC_TIME>=CURDATE()" как раз и тормозит. Отдельно и два раза работает быстрее, а вместе тормозно. В итоге стало работать шустро только после того как создал один индекс на оба поля. Но что-то мне не очень нравится такое обилие индексов.
Впрочем, для тупого подсчёта с группировкой по часам двумя запросами и делать. Но получить ответ на вопрос "а сколько всего?" нельзя. Потому что некоммутативная операция, блин. Имеем, например, сегодня 10 вставленных и 10 исполненных. Но могут быть вставленные, но не исполненные сегодня (например 2) и исполненные но не вставленные сегдня (тоже 2). Итого 14. Потому что 2+8+2. 2+8=10 и 8+2=10, но как ни крути, получить X+Y+Z невозможно, если мы знаем только X+Y и Y+Z. Ну, если очень сильно надо, то можно сделать только третий запрос, чтобы получить Y. Тогда будем иметь всё. Но вообще-то первые два запроса выполняются за 0.05, третий - за 0.06-0.07. А один OR-овый - за 0.10.
Есть ещё варианты с join-ами на одну и ту же таблицу, но это уже другая история. :)
Как я однажды уже упоминал, занялся переносом роботов с одного сервера на другой. Всё бы ничего, но на первом сервере S1 база интербейзовая, а на втором - mysql. Что, в общем-то, не проблема. Но на S1 - трастикс (старенький), а на S2 - убунта. На S1 - koi8-r дефаултом и база win1251, а на S2 - utf8.
Впрочем, ну на уникод я переползаю намеренно. Но такая разница подсовывает грабли регулярно.
Недавно писал о том, как боролся с уникодом на связке perl/apache/mysql. Хотя казалось бы раз на убунте уникод нативен, то и тут никаких заморочек быть не должно. То есть я ожидал, что везде дефаулты будут выставлены так как надо. Да хрен там.
Новая история.
На новом сервере всё начиналось с базы статистики. Т.с. с её новой реинкарнации.
Она потихоньку росла и перестала быть исключительно базой статистики.
Дошло дело до переноса базы нарядов.
Небольшая реорганизация базы, конечно, случилась, хотя относительно некоторых нововведений не уверен что решение было верным. Впрочем, переделать никогда не поздно, тем более, что до эксплуатации ещё далеко. Но как и на старом сервере база нарядов отдельна сама по себе. Хотя некоторые сущности могут перескаться. Движёк myisam-овский, если что.
Следующая база - температурная. Робот обходит датчики, сидящие на телефонных линиях, меряет сопротивление и вычисляет температуру на абонентских ступенях. На старом сервере база была сама по себе. На новом как? Генерить ещё одну базу что-то не хочется. Напрашивается создание её таблиц в одной базе с другими таблицами.
И тут как раз и напрашиваются изменения. Первая база со статистикой содержит не только статистику но и разную конфигурацию. Другим задачам тоже может потребоваться конфигурация. И что новую базу создавать, которая будет дублировать уже имеющиеся таблицы в базе статистики?
Поэтому было решено глобализовать базу статистики и перетащить в неё таблицы из базы нарядов.
Первая половина задачи получилась только с третьей попытки. Ибо rename database не нашлось, а смухлевать тупо копируя таблицы на уровне файловой системы. Да, да, копировать БД файлами может выйти боком, но в некоторых случаях это вполне приемлемый способ, если обеспечить нужные условия неприкосновенности БД на время копирования. Обеспечить-то я мог, но в старой базе ещё и функции с процедурам сидят. Я о них забыл. :) Можно было сделать mysqldump --no-data -R и выдернуть нужные определения, но где-то ещё случились глюки и какие-то таблицы тормозили. Я подумал что с индексом что-то и откатился на старые базы. На следующий день робот меня известил что несколько таблиц вообще порепались, но к тому времени я уже решил, что делать буду как положено, хоть и медленно - через бекап дампа.
Так получилась общая БД по станции, в которой будет жить всё что к ней имеет отношение. С интербейзом такое объединение было бы под вопросом. Потому что это один большой файл. Ну или несколько. Когда он становится толстым-толстым, то его и бекапить утомительно, и прочие пробемы возникают. С myisam проще - каждая таблица сама по себе. В общем, пока всё ОК и непредвиденных нежелательных последствий всё ещё не предвидится. ;)
В базе нарядов процедур не было, поэтому она перенеслась "на ура". Не помню даже - кажется копированием на уровне файловой системы перенёс. Проблем не было - поэтому и не помню.
И вот дело дошло до температуры.
Создал пару таблиц, написал скрип. Скопировал справочник скриптом. А с таблицей текущей температуры застрял.
Есть исходная таблица, есть целевая. В первой есть данные, во второй пусто. Скрипт данные из первой вынимает, во вторую складывает. Пытается складывать. То есть $db->do($stmt) проходит без ошибок, но данных в целевой таблице нет! Для простоты стейтмент содержит плоский текст. Запускаю phpmyadmin, скармливаю запрос и оп-па! Данные в таблице! Что за чертовщина? Дальше следует ещё куча танцев с бубном. Безрезультатно. То есть вот этот самый скрипт, в котором изменил только запрос недавно перенёс справочник, а температуру переносить не хочет. Родился этот скрипт из того, что переносит данные из старой базы нарядов в новую. По несколько тысяч. И не кашлянёт. А температуру не хочет.
Запускаю на первом сервере mysql и задают тот же самый запрос. Оба-на! Данные оказались на месте! То есть засада и не в базе, и не в дровах, а где-то в перле. Про незакрытую транзакцию и откат я думал, но исходные скрипты с транзакциями не работают. С транзакциями не работают, но работают, прости Господи. ;)
Кажется пытался оформить через транзакции, но меня послали. Плохо помню.
Но вот решил в соответствии с правилом "измени хоть что-нибудь" туглануть AutoCommit. О чудо! Данные оказались в таблице. Ничего не понял. В нарядах и справочнике всё работало так, а тут потребовалось иначе. Не стал заниматься разгадыванием загадки и на радостях допилил скрипт, чтобы тот обновлял данные.
Вчера занимался допиливанием веб-интерфейса.
Есть задача: нужно отобразить сегодняшние наряды. А за сутки может прийти нарядов очень много. Несколько тысяч. Выводить их все глупо. Можно выводить по страницам, но я придумал, разбивать их по группам. Например, сначала по типам услуг (дебиторка, доп.услуги, разграничением доступа). Потом, если их всё ещё дофига, то сгрупировать по времени. По часам хотя бы. Но и за час можно получить до двух тысяч. Тоже дофига. Значит нужно сгруппировать ещё более подробно, и только когда записей окажется немного, их можно выводить.
А в базе уже за два миллиона записей и группировка идёт медленно. Секунд 10 и повторный запрос ничерта не ускоряет. Стал RTFMить и пошёл юстировать параметры сервера. Добавил памяти для индексов. Пробегая по переменным удивился проблемам с InnoDB. То если удивился не проблемам, а тому что кто-то его использует. Обежал базы и обнаружил несколько с этим энджином. Медиавики, оказалось, не напрягалась относительно него. Конвертнул все что нашёл.
И вот тут-то меня и ждал сюрприз: температурная таблица создана инодбшной, ба-али-ин. Ага. А myisam транзакции не поддерживает. Собственно поэтому всё кроме температурки нормально работало, а температурка не работала потому что транзакции откатывались. Эксперимент-то я ещё проведу, чтобы убедиться.
Хотя надо всё-таки переключить сервак на дефаултовый myisam, а то уже в который раз конверченьем занимаюсь, когда забываю явно энджин указать.
А может не надо? Чтобы приучить себя всё-таки явно указывать энджин? ;)
Ах, да! Запрос быстрее работать не стал.
Тут бы explain-уть это дело. Интересно можно ли мускулю принудительно указать план как интербейзе....
Но не приучил себя к нему (по каждому чиху). :)
Собственно, закавыка тут в том, что есть поле времени (timestamp) вставки записи и исполнения наряда. Уникальных первых полтораста тысяч, а вторых - чуть больше мильёна. Каждое поле индексировано.
А "сегодняшняя" запись означает что исполнена сегодня или вставлена сегодня. И вот "INSERT_TIME>=CURDATE() OR EXEC_TIME>=CURDATE()" как раз и тормозит. Отдельно и два раза работает быстрее, а вместе тормозно. В итоге стало работать шустро только после того как создал один индекс на оба поля. Но что-то мне не очень нравится такое обилие индексов.
Впрочем, для тупого подсчёта с группировкой по часам двумя запросами и делать. Но получить ответ на вопрос "а сколько всего?" нельзя. Потому что некоммутативная операция, блин. Имеем, например, сегодня 10 вставленных и 10 исполненных. Но могут быть вставленные, но не исполненные сегодня (например 2) и исполненные но не вставленные сегдня (тоже 2). Итого 14. Потому что 2+8+2. 2+8=10 и 8+2=10, но как ни крути, получить X+Y+Z невозможно, если мы знаем только X+Y и Y+Z. Ну, если очень сильно надо, то можно сделать только третий запрос, чтобы получить Y. Тогда будем иметь всё. Но вообще-то первые два запроса выполняются за 0.05, третий - за 0.06-0.07. А один OR-овый - за 0.10.
Есть ещё варианты с join-ами на одну и ту же таблицу, но это уже другая история. :)