Первый альфа релиз phpLightOrm

Wicked

Новичок
atv
если не сложно, выложите код тестов целиком, ... А то лайторм то, наверное, используется максимально оптимально, а насчет доктрины у меня есть сомнения :)

Или мне просто тут высказать свое мнение, что там можно сделать лучше?
 

nail

Новичок
Автор оригинала: atv
Гибкость доктрины опирается на DQL, которое позволяет получать практически всё многообразие выборок языка SQL.

Я считаю, что мне удалось достичь такой же гибкости без использования DQL, благодаря API библиотеки. Конечно, возможно, я ещё не всё учёл, практика покажет.
В Doctrine DQL конструкции реализованы также в API. Так что самим "DQL" можно и не пользоваться :)
 

atv

Новичок
А то лайторм то, наверное, используется максимально оптимально...
Код взят из примеров :)

а насчет доктрины у меня есть сомнения
Код взят из примеров с офф. сайта:)

PHP:
$conn = Doctrine_Manager::connection('mysql://root:@localhost/orm');

class Seller extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('sellers');
        $this->hasColumn('seller_id as id', 'integer', null, array('primary' => true, 'autoincrement' => true));
        $this->hasColumn('seller_name as name', 'string', 30);
    }

    public function setUp()
    {
        $this->hasMany('Order', array('local' => 'seller_id', 'foreign' => 'seller_id'));
    }
}

class Customer extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('customers');
        $this->hasColumn('customer_id as id', 'integer', null, array('primary' => true, 'autoincrement' => true));
        $this->hasColumn('customer_name as name', 'string', 30);
    }

    public function setUp()
    {
        $this->hasMany('Order', array('local' => 'customer_id', 'foreign' => 'customer_id'));
    }
}

class Order extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('orders');
        $this->hasColumn('order_id as id', 'integer', null, array('primary' => true, 'autoincrement' => true));
        $this->hasColumn('order_sum as sum', 'integer');
        $this->hasColumn('seller_id as sellerId', 'integer');
        $this->hasColumn('customer_id as customerId', 'integer');
    }

    public function setUp()
    {
        $this->hasOne('Seller', array('local' => 'seller_id', 'foreign' => 'seller_id'));
        $this->hasOne('Customer', array('local' => 'customer_id', 'foreign' => 'customer_id'));
    }
}
а дальше тот код который приведен в бенчмарке.

Вообще, взяты наипростейшие варианты запросов, что там можно оптимизировать?

-~{}~ 06.03.08 12:54:

В Doctrine DQL конструкции реализованы также в API. Так что самим "DQL" можно и не пользоваться
Я за! Не буду пользоваться :)

А вот лаконичность API у LigthOrm получше будет :)
 

nail

Новичок
Навскидку:
В тестах LightORM insert/update идет внутри одной транзакции.
В Doctrine каждый insert/update создает свою транзакцию.
В InnoDB это большая разница.

Дальше можно пока не смотреть :)
 

Wicked

Новичок
1) почему доктрина версии 0.9, когда есть 0.10.2 ?
2) почему лайтормовский bulkLoad находится в секции join selecting? Почему bulkLoad'у противопоставляется join, а не loadRelated?
3) почему для лайторма стартуются транзакции, а для остальных нет?
4) тест на delete - один большой косяк. Доктрина, например, умеет делать single-shot delete, но он наверное не работает из-за пункта 3. Также весь delete код для доктрины достаточно заменить на: $conn->getTable('Order')->findAll()->delete(); или даже на Doctrine_Query::create()->delete()->from('Order')->execute() Также есть подозрение, что если определить в связях 'onDelete' => 'CASCADE', то будет еще лучше, т.к. доктрине не нужно будет обрабатывать связи самой.
 

nail

Новичок
А можно такие запросы делать с помощью LightORM?

PHP:
$q = new Doctrine_Query();
$q->select('q.*, count(si.word) as nb, sum(si.weight) as total_weight')
       ->from('Question q')
       ->innerJoin('q.SearchIndex si')
       ->whereIn('si.word', array('test1'))
       ->groupby('si.question_id')
       ->orderby('nb desc, total_weight desc');
$q->having('nb = ?',2);
 

atv

Новичок
В тестах LightORM insert/update идет внутри одной транзакции.
В Doctrine каждый insert/update создает свою транзакцию.
Какие будут предложения? Как доктрине сказать, чтоб она не создавала отдельную транзакцию?

1) почему доктрина версии 0.9, когда есть 0.10.2 ?
Я не проверял, что появилась более новая. Попробую новую.

2) почему лайтормовский bulkLoad находится в секции join selecting?
Потому что у LightOrm есть только такой режим, к тому же, он выполняется двумя запросами, что предположительно хуже. Можно отдельно сравнить ещё и с loadRelated, но такого режима нет у Propel.

3) почему для лайторма стартуются транзакции, а для остальных нет?
Разве они не стартуются автоматически.

Также весь delete код для доктрины достаточно заменить на: $conn->getTable('Order')->findAll()->delete();
В LightOrm тоже можно удалить одним запросом, но что в этом случае сравнивать? Скорость MySQL?

Также есть подозрение, что если определить в связях 'onDelete' => 'CASCADE', то будет еще лучше, т.к. доктрине не нужно будет обрабатывать связи самой.
В этом случае всем будет лучше, и LightOrm и Propel.

А можно такие запросы делать с помощью LightORM?
Можно, используя метод Collection::getItemsByQuery() и квери билдер SqlQuery. (Писать пример сейчас нет времени, я на работе)
 

nail

Новичок
Автор оригинала: atv
Какие будут предложения? Как доктрине сказать, чтоб она не создавала отдельную транзакцию?
Надо запустить транзакцию в начале.
А после цикла закоммитить, запросы будут выполнены во время коммита, как описано здесь:
http://www.phpdoctrine.org/documentation/manual/0_10?one-page#transactions
 

atv

Новичок
Надо запустить транзакцию в начале.
Ок. Позже выложу результат.

-~{}~ 06.03.08 18:02:

Исправил. Причём для Propel фишка с транзакциями тоже прокатила. Результаты для insert/update/delete существенно изменились, но всё ещё в пользу LightOrm :)

Результаты для доктрины 0.10.2 оказались даже на пару процентов хуже, а по delete стало хуже в 2 раза, так что не стал их публиковать.
 

Wicked

Новичок
atv
PHP:
// initalize a new Doctrine_Connection
$conn = Doctrine_Manager::connection($dsn);
// !! no actual database connection yet !!
(c) doctrine manual

-~{}~ 07.03.08 09:51:

вообще было бы прикольно посмотреть на тесты под микроскопом Xdebug'а

-~{}~ 07.03.08 09:56:

перенес в "новости из мира php"
 

atv

Новичок
// !! no actual database connection yet !!
Да, не учёл. Но это сказалось только на тесте insert'а, да и то, на фоне вставки 3000 связанных объектов, время подключения дало небольшую погрешность.

вообще было бы прикольно посмотреть на тесты под микроскопом Xdebug'а
Ну, на LightOrm я то смотрел, когда оптимизировал :). Да и на Propel поглядывал. По select'ам в Propel'е вытянули всё что могли, с учётом ещё и того, что она генерируемая. Так что скорость Propel'а по select'ам остаётся недосягаемой для негенерируемых ОРМ.

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

-~{}~ 21.03.08 10:49:

Вышла следующая версия LightOrm 0.2a. В новой версии исправлена проблема с автоматическим управлением памятью при вставке, обновлении и удалении объектов.

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

Результаты тестирования можно посмотреть в wiki проекта LightOrm vs Propel vs Doctrine benchmark
 

Wicked

Новичок
Воспроизвел у себя в doctrine sandbox'е модель (в Base-классах), подхачил классы для учета референсов:
PHP:
class Seller extends BaseSeller
{
    public static $instances = 0;
 
    public function __destruct()
    {
        self::$instances--;
    }
 
    public function __clone()
    {
        self::$instances++;
    }

    public function __construct($table = null, $isNewEntry = false) {
        self::$instances++;
        Doctrine_Record::__construct($table, $isNewEntry);
    }
}
Взял тест join selecting, видоизменил его до такого состояния:
PHP:
print Customer::$instances."/".Seller::$instances."/".Order::$instances."\n";

$orders = Doctrine_Query::create()
        ->from('Order o')
        ->leftJoin('o.Seller s')
        ->execute();
 
foreach ($orders as $order) {
    $sum = $order->sum;
    $name = $order->Seller->name;
    $order->free(true);
 }
unset($order);
$conn->getTable('Order')->clear();

print Customer::$instances."/".Seller::$instances."/".Order::$instances."\n";

unset($orders);

print Customer::$instances."/".Seller::$instances."/".Order::$instances."\n";
Выводит:
Код:
0/0/0
0/0/1000
0/0/0
Не знаю чо еще добавить...

-~{}~ 25.03.08 18:40:

Плюс к этому, есть буферизация, т.е. когда делаеш итерацию по таблице, в которой 10000 записей, то не беспокоишься о памяти, так как выборки происходят порциями, в зависимости от размера буфера.
Можно поподробнее? Это делается множественными запросами с limit'ом, или как?
Забыл еще спросить... а если по какой-то причине (да-да, наш мир не идеален) запрос с лимитом по трудоёмкости получается почти такой же, как без оного, не помрет ли база из-за увеличившегося числа таких тяжелых запросов?
 

atv

Новичок
Не знаю чо еще добавить...
Да, я не догадался ещё и $orders ансетить.

В тестах упомяну, как можно полностью освободить память.

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

Вобщем, это больше вопрос оптимизации базы. У нас, например, скопилось в базе до полмиллиона новостей. Естественно, начались проблемы с лимитами. Мы тогда вынесли контент новости в отдельную таблицу. И ничего, попустило.
 

atv

Новичок
Не поверишь, толко щас прошёлся по следам твоих выступлений, и наткнулся на этот же топик. :)

На твоё предложение разработчикам Doctrine оценить методику тестирования, которую я выложил, от romanb пришло письмо с поправкой на тест "Many Selecting". После моих пояснений, он отказался от неё. Других замечаний небыло, кроме общих рассуждений, что это синтетические тесты, имеющие мало общего с реальными приложениями.

Да, по поводу того, зачем я стал писать свою ОРМ. Дело в том, что изначально у меня была совсем другая идея касательно ОРМ. Но, после того, как я её опробовал на практике, отказался от неё, а ОРМку забросил. Потом, однажды, пришла другая идея. Я её положил на уже готовый каркас, кое-что переписал, и получилось ничего. А потом, строчка за строчкой начали появляться другие идеи и решения. А уже работа с памятью была последней идеей, которая появилась, когда я взялся за оптимизацию.

-~{}~ 31.03.08 13:18:

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

В отличие от Propel и Doctrine, LightOrm берёт на себя заботы по уменьшению расхода памяти.
 

phprus

Moderator
Команда форума
atv
Кстати, в этой коротенькой статье доходчиво объясняется, как перерасход памяти сказывается на производительности, и почему так важно стремиться уменьшить её расход.
30 мегабайт на процесс, 100 параллельных процессов...
Предположим что у нас каждый скрипт выполняется 0,1с. Тогда за 1с интерпретатор успеет запуститься и отработать 10 раз. Если у нас 100 параллельных процессов то мы имеем 1000 запросов в секунду. У вас есть тысяча запросов в секунду?

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

atv

Новичок
phprus, нужно было, всё-таки, не вырывать слова из контекста.

1000 запросов были приведены в статье для удобства восприятия. А то, что проблема низкой производительности существует, уж кому-кому, а битриксам известно :).

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

-~{}~ 07.05.08 08:37:

Выпущена версия 0.3а LightOrm.

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

Скачать

-~{}~ 07.05.08 08:37:

Выпущена версия 0.3а LightOrm.

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

Скачать

-~{}~ 13.05.08 12:07:

На SourceForge появилась возможность номинировать проекты. Каждый, кто имеет аккаунт на SourceForge может на странице проекта кликнуть баннер "Nominate this project". Поддержите LightOrm своим кликом :)
 

serglt

Анус, ой, Ахтунг
Приветствую. У меня тут возник вопрос к разработчику.
В документации написано что есть кэширование объектов
и приведен пример. Ставить и тестировать не хочется поэтому спрошу.
PHP:
$u1 = $users -> findFirst ();
$u2 = $users -> findFirst ();
Получается что $u1 и $u2 - это один и тот же объект
Предположим мы выбрали коллекцию пользователей, в которой присутсвует этот же объект (findFirst). Или выбрали один, но по другому условию, который на уровне таблицы тоже является (findFirst).
Дык вот собственно и вопрос: будут ли все объекты идиентичными? То есть это будет во всех случаях ссылка на кэшированный объект или же каждый будет сам по себе?
Интересует - что произойдет с объектами в коллекции и объекте найденном по условию, если я к примеру сделаю

$u1 -> name = 'Test';

Поменяется ли это свойство во всех остальных объектах
до сохранения? После сохранения?

Вообще интересен механизм подсчета ссылок, тоесть как считается ссылка на объект? Через clone?

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

Заранее благодарен.

-~{}~ 30.05.08 02:16:

UP
Hе читаем или ветку создать?:)
 

atv

Новичок
Hе читаем или ветку создать?
Читаем, читаем :), болел я просто...

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

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