24°C
завтра: 23°C
Погода в Перми
24°C
вечером20°C
ночью14°C
завтра23°C
Подробно
 64,34
+0.0165
Курс USD ЦБ РФна 19 июня
64,3352
+0.0165
 72,23
+0.1214
Курс EUR ЦБ РФна 19 июня
72,2291
+0.1214
  • Разбираюсь в доставшемся наследстве на PHP... очень много такого:

    if ( !is_null($publication) ) { return $publication; }
    else { return null; }

    $publication - сложный объект некоего класса... но разве нельзя было просто написать в одну строку:

    return $publication;

    ???

    и ещё:

    будет ли выполняться такой код?

    if ( strlen($this->$field_name) == "" ) {
    ...
    }

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

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • "if ( !is_null($publication) ) { return $publication; }
    else { return null; }"

    Не знаю PHP, но сдается мне, что там масло масляное написано...

  • С этим разобрался. Действительно так.

    А вот как обрабатывается второй пример? Из "общих соображений" вроде как: "то что справа" приводится к типу слева... но это верно для присваиваний, потому как вопрос возникает в момент "куды это теперича деть?"...
    то есть пустая строка будет приведена к числу, то есть будет число 0(ноль), а стало быть условие выполняется "в принципе верно".

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

    или действует какое-то более общее правило: целые - в вещественные, числа в строки... и т.д. т.е. приводим к тому типу, значения которого покрывают значения приводимого типа... ?!?

    Что верно в ПХП? Порядок преобразования типов конкретно для сравнений - не нашел. Может плохо искал?!?

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Главное правило программиста: работает - не трожь!

  • В ответ на: Порядок преобразования типов конкретно для сравнений - не нашел.
    Тут одним компактным местом документации не отделаться, похоже.
    "В случае, если вы сравниваете целое со строкой, строка будет преобразована к числу" (тыц)
    "Преобразование строк в числа ... Значение определяется по начальной части строки. Если строка начинается с верного числового значения, будет использовано это значение. Иначе значением будет 0" (тыц)

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

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

    З.Ы. пхп не знаю

  • По первому: пусть работает. Этого "чуда" сплошь и рядом. Замаешься править...

    По второму: вот и пытаюсь разобраться работает ли? Дело в том, что это базовый абстрактный класс перекрывающий Zend_Db_Table_Row в частности это кусок из добавленной валидации значений по признаку "not null"... от него много чего наследовано...

    Спасибо за "тыц". Похоже таки работает. На всякий случай поправил.:улыб:

    Ещё вопросик:

    Как лучше:

    1. if ( !is_null($data) ) {...}
    или
    2. if ( null === $data ) {...}

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

    или в ПХП is_null() - не вызов функции?

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • В ответ на: По второму: вот и пытаюсь разобраться работает ли?
    Что мешает поставить натурный эксперимент?

    В ответ на: 1. if ( !is_null($data) ) {...}
    2. if ( null === $data ) {...}
    или в ПХП is_null() - не вызов функции?
    А что, сравнение - это бесплатно? это тоже скорее всего будет вызов функции, учитывая, что переменные в ПХП - нетипизированы, а значит их как минимум надо привести к одному типу ну или для начала этот самый тип определить и сравнить (коль скоро три равно стоят).
    Ну и потом, есть специальная функция проверки на null, документированная.
    Зачем вы пытаетесь ее заменить "по своему разумению", из каких-то "общих соображений", так сказать? (при том, что ПХП, похоже, не знаете, как и я, кстати)

    PS
    Интересно, у вас действительно нет других задач, кроме как править работающий код "по своему разумению"? это просто вопрос, а вовсе не наезд, если что.

    Исправлено пользователем KSergey (02.02.11 18:17)

  • К сожалению, это моя основная задача на сегодня. Вот и приходится по горячему и ПХП изучать, и Зенд, и править... отсюда и вопросы.
    А писано оно, вроде как профи программистами, один из которых сейчас где-то в Москве, а другой тоже вроде как начальник ИТ отдела в крупной фирме... вот и спрашиваю, "правильно ли"...

    Вот, кстати ещё вопросики:

    метод класса getData($keys, $forform, $usecache); в своем теле имеет три генерации объекта:
    1. $products = new PartProducts(); далее через 5 строк ещё
    2. $productParts = new PartProducts(); и внутри условия ещё
    3. $partProducts = new PartProducts();

    После создания объекта типа "таблица" в ней ищется один и тот же объект (запись) по параметру $keys[0]...
    вопросы:
    1. Это приводит к трем обращениям в Мускуль, или запись в реальности у Зенда выбирается только один раз?

    2. Почему не возникает ошибка? При вызове метода в параметре всегда передается ровно одно число...

    Заменил три конструктора одним - вроде работает... а вот заменить обращение к элементу массива - боязно...

    П.С. правил метод по другой причине - параметр $forform приводил к разной заполняемости кэша данными, что было одной из причин возникающих проблем... там в одной ветке стояла полная сборка данных, а в другой - нет. Попутно нашел, что при неполной сборке, динамическая подгрузка класса работает только для старой версии адреса. А для добавленного в октябре класса Pobox - фигвам.
    ...просто "случайно" наткнулся и "оно" вызвало вопросы...

    П.П.С. попутно устранил обслуживание кэша (это был дополнительный селект в ряде методов!) - вроде стало "поживее".

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Ээээ. Я извиняюсь, что не по сути вопроса, а в чем конкретно состоит задача? Может в оптимизации кода? Так это нужно делать профайлером, иначе получается борьба с приведениями. .А в профайлере четко будет видно где пробки

  • А в профайлере кругом "попа". Примерно одинаковая: выборка данных в несильно большой базе в среднем 2-40сек., и зависит больше от нагрузки на сервер (много join и как следствие блокировок). И связано как раз с наличием, практически везде, повторных обращений по генерации вспомогательных объектов с доп.выборками... примерно в каждом методе раза по три... или вложенные вызовы методов по 3-6 раз за одним и тем же... Вот сейчас из-за этого переписал класс Сategories.php.

    Так, например, данные по доступности ресурсов для пользователя (ключи доступа) в объекте пользователя дублируются трижды , причем все, в смысле каждому пользователю собирается массив всех ключей базы трижды... где "это" пока ещё не нашел... "Итого" объект user содержит более 30_000 элементов!

    Ну или вот автор подсистемы "списки фирм" (задания манагерам) зачем-то спроектировал таблицы так, что чтобы показать остаток недораспределенного списка (сколько ещё свободных фирм) делает в запросе подсчет по каждой строке разницы между общим количеством и суммой (отдельный подзапрос!) рапределенных записей... вместо того, чтобы просто хранить это число и контролировать его изменение по необходимости... результат: загрузка страницы со списками у начальника отдела "грузится" от 2 до 8 минут!!! Ну "куда это годится"?

    А тот автор, который уже в Мск - зачем-то создал Мускульную процедуру разбора json строки для реализации расширенного поиска по базе... Я вот первый раз увидел как на мускуле можно синтаксические анализаторы писать... Сколько времени может работать такой "поиск", думаю оцените самостоятельно.:улыб:

    Щас, ещё сижу осваиваю JS... потому как на стороне клиента обработка страницы может занимать от 0,5 до 3 минут.:хммм:

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

    П.С. все-таки, хотелось бы получать ответы на вопросы, а не "филосовствовать"...

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • все понятно, что ничего не ясно:улыб:
    Где-то кэш нужно пользовать, где-то redundant данные вместо постоянных вычислений, где-то зарефакторить все нафик.
    Сочувствую вобщем. Будут вопросы по java обращайтесь:миг:

  • Спасибо. Помощь понадобится по js. Чистой java тут ещё нет практически.

    По заданным вопросам разобрался сам:
    1. Нифига, все три генерации объекта приводят к запросам в БД.
    2. Ошибки не возникает, не знаю почему... возможно генериться какой-нибудь варнинг, но они похоже давятся...

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

    Исправлено пользователем tolstopuz (03.02.11 17:59)

  • ... слов нет... Модераторы, прошу снести три предудыщих сообщения. Запаковал оба файла. Кодировка utf-8...
    Вторая попытка.

    Ещё раз, интересует как полезность изменений в коде, так и полезность такого документирования... может существуют какие-то более принятые стандарты? Все вызовы просмотрены grep`ом и поправлены. Код пока работает нормально.

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • жэсть....
    откройте для себя doxygen например.
    и не пишите комментарии на русском - НИКОГДА. ну или готовьтесь встретить в чужом коде комментарии на хинди/китайском.

    Non solum oportet, sed etiam necessese est

  • В ответ на: или готовьтесь встретить в чужом коде комментарии на хинди/китайском.
    Ну я встречал, и чё? не умер. Поразительно, правда?

  • Спасибо, посмотрю. Но, наскольк посмотрел аннтотацию - это система генерирования документации. Замечательно, но для быстрой правки кода, наличие комментов в самом коде (особенно большом и такого) намного производительнее. Поэтому комментарии, ПХП-док - давно и не мной придуманы.

    Комментари - для наших простых русских парней. В первую очередь "для себя любимого"... нафиг мне самому себе писать на английском или китайском?:миг:По поводу полезности комментов "для себя" - спорить не буду. Вы может и способны помнить весь код объемом в 6.5 мегабайт, я вот - нет. А судя по повторным созданиям объектов и дубликатам кода - тот кто так считал - на практике оказалось, что тоже нифига не помнит.

    А "по существу", что нибудь подскажете?

    Меня интересует:
    1. Правильность оформления ПХП-док. То, что в заголовке класса помещать перечень методов нет смысла - уже понял. Средства Eclipse позволяют обходится без этого.
    2. "Стилевые и оптимизирующие" правки кода:
    а) Устранение промежуточных возвратных объектов. То есть перенос в оператор return последнего оператора метода.
    б) создание промежуточных методов, которые по-просту устранят повторы кода в нескольких местах. Здесь это метод _getUserKeys(). Как оказалось - он ваще не нужен. Все ключи можно достать из контроллера, они там уже приготовлены...
    в) оптимизация запросов. Здесь фактически произведена замена обращений к NestedSet на выборку по полю parent, которое практически содержит прямую ссылку на родителя.
    г) изменение схемы вызова методов? Которое привело здесь к тому что теперь фактически методы getCategoriesArray, getNamedArray (бывший getCategoriesArray2Select) и кусок кода из getForm - по сути теперь новый метод, через который они все работают.
    ИМХО достоинства:
    1. Собственно выборка данных теперь в одном месте (потенциально - уменьшение ошибок).
    2. Новый метод - универсален и позволяет делать много новых выборок и индексаций массивов.
    3. Это просто стало понятнее как работает, или нет?

    г) Насколько второй текст лучше понимается чем первый?
    д) Насколько второй текст быстрее (и/или) менее объемен по данным первого?

    Небольшой итог: Время переработки кода в целом заняло около 16-и часов. Из них:
    1. около 8-и часов - это разбор набора таблиц этой части базы, кода класса (что это?) и анализ мест вызова (зачем это?). Попутно исправлено 2 мелких ошибки в местах вызова и устранен не нужный класс Filter. Как потом оказалось неполностью. Объекты класса еще создаются в html коде...
    2. около 5-и часов заняло изменение собственно кода методов и мест вызова, где потребовалось. Долго, потому что с ПХП - я ещё далеко не на "ты".... много приходится лазить по документации...
    3. около 2-х часов заняло документирование.
    4. отладка кода заняла ещё около часа. Заработало с третьего раза.
    Ошибки: 1. неправильное указание параметров в одном из вызовов.
    2. Обнаружены вызовы из html.
    3. При правке getParentsItems - забыл, что надо таки возвращать массив а не Rowset.

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • я и не говорил, что умрете.

    Non solum oportet, sed etiam necessese est

  • phpdoc vs doxygen
    фильтр php для doxygen
    а учитывая, что в проекте может использоватся не один яык (php) а несколько (+python/java/plsql/etc) то имхо это вообще единственная нормальная система документирования, позволяющая сгенерировать документацию для всего проекта.

    В ответ на: 3. Это просто стало понятнее как работает, или нет?
    если честно - разницы почти нет. кстати, не всегда стоит писать "универсальные методы, позволяющие исключить дублирование кода" - восприниматся сложнее начинает.

    Non solum oportet, sed etiam necessese est

    Исправлено пользователем Mad_Dollar (06.02.11 11:05)

  • Остальное комментировать, как понимаю не будете.
    Просто, поскольку ПХП не знаю, надеялся на более обширное обсуждение, в том числе и Ваше, как специалиста.

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

    Все равно, спасибо и на этом.

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • ну а что там комментировать?

    в общем случае оптимизация - сущность измеряемая. если вы можете измерить ее - можно объективно оценить ценность правок. оценка просто "куска кода", без знания где в какой системе, как часто он выполняется и насколько критичен для работы - вопрос сферического коня в вакууме.

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

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

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

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

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

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

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

    Non solum oportet, sed etiam necessese est

  • БД, на сегодня, перегружена выше всякой меры. Уже писал об этом: 30-40 юзверей валят 4-х ядерный сервер, потому как на получение одной странички делается до 100 запросов в БД. Время отклика на сегодня "в среднем" от 30 секунд до 5-и минут! Писал же.

    Это - базовый класс (один из десятка), через который работает вся система публикаций... подача баннеров в СМИ, корректура, верстка печатных СМИ, отчеты о проделанной работе и т.д.

    Рефакторинг дал:
    1. одно обращение к БД на один объект класса. В частности метод getParentItems, getCategoriesNamedArray - вместо просмотра в цикле узлов NestedSet - просто делают один запрос соединяя таблицу класса саму с собой для получения названий групп категорий. Один запрос против десятка (в среднем) для обхода дерева. На одну страничку выдачи, генерилось до 5-и таких объектов. В среднем - 2-3. Теперь 1, и только там где надо 2 (список категорий для выбора и те категории, по которым есть публикации).

    2. Снижен уровень вложенности вызовов, практически с 4-5-и до 2-х. Раньше (здесь не очень видно): вызов статметода класса Filter, создание объекта, обращение к методу... в нем - ещё 3 вложенных вызова до БД. Теперь: создание объекта - обращение к методу и в нем вызов универсального метода.

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

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

    П.С. посмотрел doxigen. Спасибки, хорошая вещица, сильно поможет для генерации общей документации. Буду делать, потому как числа с 15 февраля планирую открыть общий доступ в наш СВН для привлечения фрилансеров...
    но, к сожалению, программ, которые бы телепатически догадывались о назначении классов, параметров и целей их взаимосвязей с БД - ещё не придумали. Так что в "повседневной" правке - лично мне, врядли поможет. Без наличия комментов в коде, она мало чем помогает, а они отсутствуют как класс, уже писал об этом.

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

    Профайлер на предмет "что это дало конкретно" ещё не смотрел, но ряд страниц теперь грузится практически мгновенно по ощущениям...:улыб:

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

    Исправлено пользователем tolstopuz (07.02.11 09:29)

  • В ответ на: Уже писал об этом: 30-40 юзверей валят 4-х ядерный сервер, потому как на получение одной странички делается до 100 запросов в БД. Время отклика на сегодня "в среднем" от 30 секунд до 5-и минут!
    ну я вам так скажу - нужно тюнить БД и рефакторить не пэхопэ, а схему данных... у меня селект на over 40M строк на восьми полноценных ядрах (ибо гипертрейдинг это не полноценное ядро) занимает 1-2 секунды.
    смотрите локи, смотрите рекомендации mysqltuner.pl (http://mysqltuner.pl/mysqltuner.pl), в конце концов - очень вероятно возможно что стоит больше денормализовать БД и покрутить настройки.
    опять же - у меня на одну страницу до пятисот запросов - ничего, 1-2 секунды в среднем, если не используются тяжелые таблицы с миллионами строк - менее секунды. это необходимые издержки объектно-ориентированного кода с объектно-ориентированными универсальными прослойками методов.
    В ответ на: Снижен уровень вложенности вызовов, практически с 4-5-и до 2-х.
    если вы используете транзакции для селектов это не даст выигрыша. ибо кэш запросов и транзакции, хотя все зависит от размера кэша.
    В ответ на: но, к сожалению, программ, которые бы телепатически догадывались о назначении классов, параметров и целей их взаимосвязей с БД - ещё не придумали.
    взаимосвязи с БД - да, а вот описание структуры классов, методов и параметров вызовов делается полное. И если не называть методы DoOne, DoTwo и не передавать им переменные A, B, C (что относится и к именам классов), то в принципе даже без комментариев документация генерится сносная - даже без docblock'а.
    В ответ на: Профайлер на предмет "что это дало конкретно" ещё не смотрел, но ряд страниц теперь грузится практически мгновенно по ощущениям...
    а это единственный показатель нужности =)

    Non solum oportet, sed etiam necessese est

  • В ответ на: опять же - у меня на одну страницу до пятисот запросов
    :eek:
    Я всегда любил любителей ООП над БД...

  • В ответ на: это необходимые издержки объектно-ориентированного кода с объектно-ориентированными универсальными прослойками методов
    ... как-то далеко не уверен. ООП - в своей основе - это табличное программирование, которое всегда было самым компактным и самым быстрым... в мое время. Оно канечна, "всё течёт, всё изменяется", но не до такой же степени!:улыб:
    В ответ на: нужно тюнить БД и рефакторить не пэхопэ, а схему данных
    Этим тоже занимаюсь.
    Так например вот это:

    $select->from(array('cl' => $this->_name), array(
    'id' => 'cl.id',
    'name' => 'cl.name',
    'created_at' => 'DATE_FORMAT(cl.created_at, \'%d.%m.%Y\')',
    'companies_count' => 'COUNT(DISTINCT ccd.id)',
    'begin_date' => 'ccf.begin_date',
    'end_date' => 'ccf.end_date',
    'not_distributed' => 'COUNT(DISTINCT ccd.id) - COUNT(DISTINCT ccp.id)',
    'creator_name' => "CONCAT(IFNULL(p.lname, ''), ' ', IFNULL(p.fname, ''))",
    'allow_edit' => 'NOT ISNULL(ccf.begin_date)',
    'isowner' => 'IF(cl.created_by = ccf.owner, true, false)',
    'ccf_id' => 'ccf.id'
    ))
    ->joinLeft(array('ccf' => 'clists_m_company_function'), 'ccf.list_id = cl.id', array())
    ->joinLeft(array('ccd' => 'clists_company_department'), 'ccd.clists_m_company_function_id = ccf.id', array())
    ->joinLeft(array('dw' => 'm_division_worker'), 'dw.m_company_function_id = ccf.m_company_function_id', array())
    ->joinLeft(array('cp' => 'm_company_people'), 'dw.m_company_people_id = cp.id', array())
    ->joinLeft(array('u' => 'usr_users'), 'u.`data_type` = \'m_company_people\' AND u.data_id = cp.id', array())
    ->joinLeft(array('u2' => 'usr_users'), 'u2.id = cl.created_by', array())
    ->joinLeft(array('cp2' => 'm_company_people'), 'u2.data_id = cp2.id AND u2.data_type = \'m_company_people\'', array())
    ->joinLeft(array('p' => 'm_people'), 'p.id = cp2.m_people_id', array())
    ->joinLeft(array('ccp' => 'clists_m_company_people'), 'ccp.clists_m_company_function_id = ccf.id', array())
    ->where('u.id = ?', $user);

    выбиралось за время более 20-и минут, в зависимости от нагрузки на мускуль. Да ещё и неправильно делаются подсчеты. Так для списка из 2405 фирм, в результате показывается companies_count = 10848... и это при том, что в базовой таблице всего ... 12 списков.

    Убрал ВСЕ вспомогательные таблицы, добавив всего 4 поля в таблицу фирм списка 'clists_m_company' (вместо clists_m_company_function и clists_m_company_departments): `department_id`, `manager_id`, `for_deps_at` и `for_mans_at`, опираясь на то, что фирма из списка, может быть назначена единовременно только одному менеджеру и дополнительное условие что менеджер может быть назначен только после назначения отделу... весь запрос превратился в простой подсчет количества записей с заданным и пустым manager_id и department_id с группировкой по заданному списку... время отклика всей страницы... менее 2 сек.

    Итого, от системы списков осталась таблица имен списков и таблица фирм этих списков с текущим указанием какая - кому назначена... всё.:улыб:

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • В ответ на: ну я вам так скажу - нужно тюнить БД и рефакторить не пэхопэ, а схему данных...
    В общем случае - не соглашусь. Ибо как один дурак может задать столько вопросов, что на них не ответит и сотня мудрецов, так и одна дурацки написанная программа может загрузить на 100% любой сервер.

  • ну дураки разные бывают, предполагается что "дураки" не "полные овощи", так как все-таки программистами писаны. да и мудрецы "подзаточены под дураков".

    при объемах в 70 тысяч строк и селектах по нескольку секунд (с несколькими джойнами, но все-таки будем считать размер таблиц ДО 100 тысяч строк) рефакторить нужно именно схему данных, или я чего-то не понимаю?

    Non solum oportet, sed etiam necessese est

  • В ответ на: при объемах в 70 тысяч строк и селектах по нескольку секунд (с несколькими джойнами, но все-таки будем считать размер таблиц ДО 100 тысяч строк) рефакторить нужно именно схему данных, или я чего-то не понимаю?
    Нужно смотреть и то, и другое. Я не раз сталкивался с ситуациями, когда программы
    (не мои :)) прекрасно вели себя в разработке, но при выходе на рабочую нагрузку вешали все, что только можно. Причина - неоптимальная работа с базой данных. Если страница делает 100 запросов к серверу, с одной такой страницей он справится прекрасно, а вот когда клиентов будет не 1-2, а 100 или 1000, все становится уже не так весело. Можно конечно поставить 4-8 процессорный сервер или даже кластер для обработки большого объема запросов, но чаще такие проблемы бывают от криво написаного кода.

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

  • "Рефакторить схему" - оно конечно надо. Но вот приведенный выше запрос, у меня в первую очередь вызвал такой простой вопрос:

    Зачем надо было вычитать в запросе один Count() из другого, для каждой записи? Разве нельзя это сделать уже позже на ПХП... и значительно быстрее?
    А ежели учесть, что при таких джойнах записи легко "размножаются" в выдаче, то как таким запросом можно рассчитывать на получение правильных чиселок?

    "профи" могут рассказать, где тут "собака порылась"?:улыб:

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Ну вот заработало. После добавления указанных выше полей и изменения назначения поля created_by в основной таблице имен списков (clists) на ссылку с пользователя системы на ссылку в сотрудники отдела... вышеприведенный запрос стал выглядеть так:

    SELECT
    cl.`id`, cl.`name`, cl.`begin_date`, cl.`end_date`, cl.`created_at`,
    cl.`companies_count` AS cnt,
    COUNT(cfn.`id`) AS not_distributed,
    CONCAT_WS(' ', mp.`lname`, mp.`fname`) as creator_name,
    NOT ISNULL(cf.`for_deps_at`) as allow_edit,
    IF(cf.`m_division_worker_id` = mdw.`id`, true, false) as is_owner
    FROM `clists` AS cl
    JOIN `clists_m_company` AS cf ON cf.`list_id` = cl.`id`
    LEFT JOIN `clists_m_company` AS cfn ON cfn.`id` = cf.`id`
    AND (cfn.`m_company_function_id` IS NOT NULL) AND (cfn.`m_division_worker_id` IS NULL)

    JOIN `m_division_worker` AS mdw ON mdw.`id` = cl.`created_by`
    JOIN `m_company_people` AS mcp ON mcp.`id` = mdw.`m_company_people_id`
    JOIN `m_people` AS mp ON mp.`id` = mcp.`m_people_id`

    GROUP BY cl.`id`
    ;

    ... и выполняться за 0.2 сек.

    Или я где-то "не догоняю" или "нафига было так делать"?

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • А вот такая редакция дает 54мс:

    SELECT
    cl.`id`, cl.`name`, cl.`begin_date`, cl.`end_date`, cl.`created_at`,
    cl.`companies_count` AS cnt,
    SUM(IF(
    (NOT ISNULL(cf.`m_company_function_id`)) AND ISNULL(cf.`m_division_worker_id`),
    1 , 0)) AS not_distributed
    CONCAT_WS(' ', mp.`lname`, mp.`fname`) as creator_name,
    NOT ISNULL(cf.`for_deps_at`) as allow_edit
    IF(cf.`m_division_worker_id` = cl.`created_by`, true, false) as is_owner
    FROM `clists` AS cl
    JOIN `clists_m_company` AS cf ON cf.`list_id` = cl.`id`

    JOIN `m_division_worker` AS mdw ON mdw.`id` = cl.`created_by`
    JOIN `m_company_people` AS mcp ON mcp.`id` = mdw.`m_company_people_id`
    JOIN `m_people` AS mp ON mp.`id` = mcp.`m_people_id`

    GROUP BY cl.`id`
    ;

    П.С. подправил "кто собственник" для наглядности.

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

    Исправлено пользователем tolstopuz (10.02.11 15:29)

  • Я ту конструкцию в виде какого-то пхп подобного ORM запроса вообще не понял, и догадываться было неохота, а тут мне кажется для подсчета cfn джоинить хуже чем выполнить отдельный subselect, хотя может execution plan будет и одинаковый, надо смотреть. И вообще group by id как-то не смотрится (потому и заметил), т.е. вместо

    COUNT(cfn.`id`) AS not_distributed,

    я бы написал нечто вроде

    (select count(1) from clists_m_company cfn where cfn.id = cf.id) AS not_distributed,

    а левый джоин убрал бы нафик

  • а зачем в новой редакции GROUP BY cl.`id` ?

  • Замена джоина на сабселект это к вопросу о читабельности кода.
    Если сабселект понятен и однозначен (и query оптимайзеру тоже), то левый джоин с count ом и group by id вызывает легкий несколькосекундный ступор - "нахуа"

  • В ответ на: а зачем в новой редакции GROUP BY cl.`id` ?
    Иначе SUM не сработает

  • а, ну да

  • "Перевел" на SQL то, что было ранее выдано из ПХП кода. Заодно немножко перегруппировал, дабы было понятнее.
    Зачем здесь нужна вторая группа джойнов - так и не понял. Они, вроде как, ваще НЕ используются. А третья группа, относится к получению ФИО автора списка.

    SELECT cl.id AS id, cl.name AS name, cl.created_at AS created_at,
    COUNT(DISTINCT ccd.id) AS companies_count,
    ccf.begin_date AS begin_date,
    ccf.end_date AS end_date,
    COUNT(DISTINCT ccd.id) - COUNT(DISTINCT ccp.id) AS not_distributed,
    CONCAT(IFNULL(p.lname, ''), ' ', IFNULL(p.fname, '')) AS creator_name,
    NOT ISNULL(ccf.begin_date) AS allow_edit,
    IF(cl.created_by = ccf.owner, true, false) AS isowner,
    ccf.id AS ccf_id
    FROM `clists` AS cl
    LEFT JOIN clists_m_company_function AS ccf ON ccf.list_id = cl.id
    LEFT JOIN clists_company_department AS ccd ON ccd.clists_m_company_function_id = ccf.id
    LEFT JOIN clists_m_company_people AS ccp ON ccp.clists_m_company_function_id = ccf.id

    LEFT JOIN m_division_worker AS dw ON dw.m_company_function_id = ccf.m_company_function_id
    LEFT JOIN m_company_people AS cp ON dw.m_company_people_id = cp.id
    LEFT JOIN usr_users AS u ON u.`data_type` = 'm_company_people' AND u.data_id = cp.id

    LEFT JOIN usr_users AS u2 ON u2.id = cl.created_by
    LEFT JOIN m_company_people AS cp2 ON u2.data_id = cp2.id AND u2.data_type = 'm_company_people'
    LEFT JOIN m_people AS p ON p.id = cp2.m_people_id
    ;

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Щас вот вывалился Auth.php... апосля того, как добавил в его инициализацию дополнительную выборку из базы параметров "сотрудник", "сотрудник отдела", "ФИО"... это дабы такие джойны поубивать ваще из всех запросов нафиг... (по три таблицы, как в примерах выше)

    ... оказалось, что плагин запускается раньше, чем происходит инициализация всех настроек в ZendRegistry ... при попытке выборки из БД дополнительных данных - выдал ошибку "не установлен параметр в ZendRegisry"...

    Вот и ещё вопросик: в каком порядке лучше проводить инициализацию в index.php?:улыб:

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Вы бы уж весь исходник выложили - да и набирали группу энтузиастов для поддержки:улыб:
    А то как-то не понятно уже к чему весь этот поток мыслей.

  • Весь сюда, пожалуй не влезет. Он, думаю побольше чем весь этот сайт, причем раз в несколько.

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

    1. Как лучше: 1) if ( !is_null($data) ) {...} или 2) if ( null === $data ) {...} ... или в ПХП is_null() - не вызов функции?
    Практически разобрался сам...

    2. Зачем надо было вычитать в запросе один Count() из другого, для каждой записи? Разве нельзя это сделать уже позже на ПХП... и значительно быстрее?
    ... ну, фактически вопрос закрыт. По факту: 33.5минуты против 54мсек., "мелочь, а приятно".:миг:

    3. А ежели учесть, что при таких джойнах записи легко "размножаются" в выдаче, то как таким запросом можно рассчитывать на получение правильных чиселок?
    ... тоже.

    4. Вот и ещё вопросик: в каком порядке лучше проводить инициализацию в index.php?
    ... пока осталось. Сижу, читаю Зенд, сравниваю в коде... пытаюсь "переварить".

    Вот, где-то так. Ещё раз: ПХП, Мускуль, Зенд - я ещё только осваиваю...
    Как оказалось, на "помощь" рассчитывать - не приходится. "Знатоки" - примерно такие же как и те, кто это писал - как и сам на сегодня.

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

    А так, в принципе, тему можно закрывать. Исходники будут в доступе (из SVN) с 15-го февраля, для всех фрилансеров, желающих подработать.

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • .

    Исправлено пользователем KSergey (10.02.11 22:54)

  • ищите проф. форумы, к примеру

    http://www.sql.ru/forum/actualforum.aspx

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

  • пасибки. Посмотрел, есть чего почитать... очень нехватало.

    Понравился FAQ по мускулю... особенно статья о деревьях.

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Возник ещё вопросик:

    Добавляю в класс, наследник Zend_Db_Table (работа с таблицей мускуля) константы, содержащие наименования полей...
    Оказалось достаточно удобно, а главное "не ошибешься" в написании...
    Но тут вот задумался: если я, используя класс в другой модели, обращаюсь только к константам класса - будет подгружаться весь файл класса, так ведь? А если в БД 300 таблиц... то "в пределе" можно загрузить все классы, так чтоли?

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

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

  • Спасибки всем, с последним вопросом разобрался так:
    Классы-наследники Zend_Db_Table дополнил:
    1. Наименования полей из таблицы БД - как константы класса.
    2. Метод класса, возвращающий строку join, leftjoin.
    Кроме этого добавил несколько простых обычных функций:
    1. по формирование строки "where" из mixed параметра (null, int, string, array), которая правильно использует "=", "is null", "in()"
    2. преобразование массива Rowset в простой массив "ключ"=>"значение".

    Оказалось очень удобно. Теперь если надо изменить структуру таблицы класса - достаточно только добавить/изменить константы класса. Код лопатить - нет никакой нужды. А главное больше не надо каждый раз пялиться в БД и смотреть какие там поля в таблице ишо есть...

    "Только так, только личная инициатива и напряженная работа над собой. Вот я вас хочу именно к этому призвать .. Нужно своей собственной рукой все делать" (с) В.В. Путин :)

Записей на странице:

Перейти в форум

Модератор: