Оптимизация использования моделей от Active Record, и немного массивов

    Сделал я недавно некий тест, который выдал любопытные данные. Коими хочу поделиться, дабы помочь многим прояснит спорные ситуации.
    Везде только и пишут, что насколько быстры массивы, насколько медлителен Active Record… Но когда видишь конкретные цифры гораздо легче понимать что на сколько лучше другого.

    Используемые материалы:


    — обычный ноутбук: Intel core 2 duo 2.13GHz, RAM 6 GB
    — php 5.3
    — apache 2.2
    framework Yii 1.1.10
    Active Record



    Описание теста:


    Существуюет класс —
    class Address extends CActiveRecord { … }

    Есть цикл из миллиона(1 000 000) итераций. На каждой итерации:
    1. Объявляется новый объект и заполнялся данными.
      $address = new Address();

    2. Используется паттерн singlton — объект объявляется один раз и на каждой итерации и перезаполняется.
      $address = Address::model();

    3. Объявляется и заполняется массив.
      $address = array();

    4. Простой stdClass().
      $address = new stdClass();

    5. Объявляем объект (как в варианте 1) но без инициализации всех сопутствующих данных AR
      $address = new Address(null);



    Результаты (сек.):


    1. 28.490615844727
    2. 7.2354989051819
    3. 4.5744869709015
    4. 5.9930000305176
    5. 9.5185680294037


    Выводы:


    • Конечно же для хранения и обработки данных можно использовать объекты, а не только массивы.
    • Конечно же классы можно наследовать от CActiveRecord, даже если не собираешься использовать классический подход Active Record – для этого не забываем добавлять null в конструктор (обращаю внимание — не false, не пустую строку, не 0):
      $address = new Address(null);

      и избегать записи:
      $address->attributes = $_POST['Address']

      т.к. при этом все равно происходит подключение мета данных AR и увеличиться время работы объекта.
      Делаем присвоение в ручную:
      
      $address->street = $_POST['Address']['street'];
      

    • Конечно же нужно использовать метод – model() – Осторожно! Это касается Yii < v.2
    • Не стоит упираться только в массивы – их тоже надо использовать с умом. По удобству они не идут практически ни в какое сравнение с объектами.
    • Самый главный вывод в том, что надо всегда (включать мозги) находить «золотую середину» между скоростью разработки продукта и скоростью работы продукта. К примеру, если в день нет хотя бы 50 000 посещений и нет выводов списков каких-то данных из базы на сайте, то про массивы вообще можно забыть и не вспоминать пока не появиться узкое место и не будет тормозов.


    Хочется узнать, почему же класс, наследуемый от ActiveRecord тратит так много времени. В результате тестов, мы видим, что в основном время затрачивается на инициализацию/присвоение свойств/элементов, т.е. чем больше приходится использовать свойств/элементов тем дольше будет работать объект/массив. А поскольку ActiveRecord должен описывать в себе все поля таблицы (для этого существует классы CActiveRecordMetaData и CmysqlTableSchema и CmysqlColumnSchema у которых своих свойств дофига), то на это описание мета данных и тратиться основное время исполнения класса наследуемого от ActiveRecord.
    Из этого можно сделать

    еще Выводы:


    • Чем больше столбцов в таблице, которую будет поднимать ActiveRecord, тем дольше наш класс будет инициализироваться.
    • Обратите внимание, что это не зависит от того, сколько вы полей поставите в SELECT – мета данные в любом случае будут подниматься все (если я, конечно, не ошибаюсь). И на против, от количества полей в SELECT будет напрямую зависеть скорость работы DAO.


    Пример тестового кода:



    
    public function actionIndex() {
            $mk = microtime(true);
            for ($i = 0; $i < 1000000; $i++) {
                $this->test1();
            }
            echo microtime(true) - $mk, '< br/ >';
    …
    
    }
    
    public function test1(){
            $address = new Address();
            $address ->zip = 3423423;
            $address ->state_ id  = 23332;
            $address ->house = 2234;
            $address ->street = 'asdfasdf';
            $address ->street_type = 'asdfasdfasdfsdf';
            $address ->address = 'asdfasdfsdf';
            $address ->code = 's';
            $address ->name = 'asdfasdfasf';
            $address ->latitude = 23.23232;
            $address ->longitude = 23.342342;
    }
    


    Остальное по аналогии.

    PS


    1. Обращаю внимание, что этот тест затрагивает только php и никоем образом не зависит оптимизаций mysql или apache.
    2. Стоит учитывать то, что временные данные тестов это не идеальное время работы массива или объекта в идеальных условиях, но позволяют сравнить скорость работы относительно друг друга.


    PPS


    Класс Address() выдуман и свойства выбраны приблизительно по смыслу.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 27

      0
      Еще очень замедляет и утяжеляет приложение использование relations, поэтому выборки, где есть связанные модели, нужно делать с помощью DAO. Далее для сохранения логики можно применить паттерн flyweight к выбранным данным. В данном случае, конечно, полагаться на механизм релейшнов для отображения не стоит.
        0
        >Еще очень замедляет и утяжеляет приложение использование relations, поэтому выборки, где есть >связанные модели, нужно делать с помощью DAO

        На самом деле — жадная загрузка по реляциям не медленнее чем при использовании DAO. А удобство разработки дорогого стоит.
        +2
        И на против, от количества полей в SELECT будет напрямую зависеть скорость работы DAO.
        ну ушь не напрямую прям, все таки не на GPRS канале связь с бд идет… я надеюсь.
          +3
          Учитывая реалии сегодняшнего дня, в вашем тесте есть пара фундаментальных недоработок:
          • PHP 5.4 — нужно использовать его, т.к. в нём весьма прилично оптимизировали объекты. Как по CPU, так и по памяти. Разница достаточно сильная.
          • ActiveRecord читает метаданные таблиц по умолчанию из базы на каждый экземпляр объекта. schemaCachingDuration вам в помощь, поскольку без него и так понятно, что всё будет мрачно.
          • Потеря удобства разработки, причём это может сказаться на времени исполнения крайне негативно.
          • Ну и в реальности никто не будет перебирать такие объёмы через AR если есть требования к скорости выполнения, а так же скушает слишком много памяти.
            0
            Вы не поняли сути поста. Так сказать, фундаментально сморозили чушь.

            1. В любом случае не будет работать быстрее массивов, а то что быстрее так это хорошо
            2. А представляете, если использовать Кэширование страниц, вообще не придется обращаться к AR
            3. Вообще пункт в пустоту
            4. Это и так понятно, зачем нужно было сюда это писать, не понимаю…

            Цель поста, показать на примере и цифрах Почему и Где и При каких Конкретно условиях и в Каких границах можно или нельзя использовать AR или массивы. Наглядно показать.
              0
              Отвечаю на претензию по поводу schemaCachingDuration уважаемому Psih

              system.db.CDbCommand.query(SHOW COLUMNS FROM `address`) 1 0.00501 0.00501 0.00501 0.00501
              system.db.CDbCommand.query(SHOW CREATE TABLE `address`) 1 0.00318 0.00318 0.00318 0.00318

              Кеширование мета данных ни как не связно с вводом данных в объект. Кеш schemaCachingDuration отвечает только за то, будет ли php обращаться за мета данными в базу или нет.
                0
                В данном примере при создании модели она будет обращаться в базу за своей структурой. Кеш её считывание и разборку уберёт, позволив быстро создать нужные внутренние объекты.
                  +3
                  В данном примере я же доступно показал, что мета данные кешируются. Не тупите.
                    0
                    Считывание уберёт, разобрку уберёт далеко не всю.
                –7
                Было бы неплохо, если бы в заголовке указывалось, что речь идёт о PHP. А то по названию ожидаешь руби.
                  +3
                  ActiveRecord уже с руби стал ассоциироваться? Я по хабам понял про что речь.
                    +4
                    Просто в узком кругу ограниченных людей, слово ActiveRecord ассоциируется с конкретной библиотекой, а не с паттерном.
                      –7
                      Ну уж простите нас, ограниченных. Куда нам до многомудрых полугениев.
                        0
                        А вы самокритичны.
                        +1
                        В посте, похоже, тоже ассоциируется с конкретной библиотекой.
                          0
                          Ну как бы да, но есть же хабы, говорящие для какого фреймворка и для какого языка этот пост. Как по мне проблема с заголовком слегка преувеличенна. Хотя да, указание что это ORM в Yii было бы не лишним.
                            +2
                            К сожалению в RSS не отображаются хабы.
                        0
                        Почему «стал»? Сравните количество результатов в поиске по «activerecord ruby» и «activerecord php».
                        А хабов в гугль ридере не видно.
                          +2
                          Сравните количество результатов в поиске по «activerecord ruby» и «activerecord php».


                          Аргумент!
                        +2
                        Active Record есть только в Ruby? :)
                            0
                            Конечно же классы можно наследовать от CActiveRecord, даже если не собираешься использовать классический подход Active Record


                            Зачем?
                              0
                              Извиняюсь, нажалось не туда :)
                          0
                          Конечно же классы можно наследовать от CActiveRecord, даже если не собираешься использовать классический подход Active Record


                          Зачем?
                            +1
                            Чтоб использовать другие удобные функции CActiveRecord, которые уже написаны и протестированные. К примеру этот класс нормально так подходит для базового класса моделей (хотя у меня еще дополнительная прослойка-класс существует).
                            Причем, бывают случаи, когда все же лучше использовать подход AR — хоть в той же админке, где не нужна скорость а нужен комфорт и надежность. Не создавать же теперь две разные модели.
                              +1
                              Ну, если иногда пользоваться, иногда нет, тогда всё верно.
                            0
                            Хороший лаконичный пост.
                            Рад видеть на хабре, кстати. сначала открыл посмотрев только на называние, думал скинуть тебе, а потом оказалось что ты автор ;)

                            Only users with full accounts can post comments. Log in, please.