2015-08-08 5 views
5

У меня есть огромный стол продукции (100k + строки) и в моем контроллере У меня есть следующие функции:Как я могу улучшить скорость KnpPaginatorBundle и Doctrine?

public function indexAction(Request $request) 
    { 
     $findProducts = $this->getDoctrine() 
      ->getRepository("StockBundle:Product")->findAll(); 

     $paginator = $this->get('knp_paginator'); 
     $producten = $paginator->paginate(
      $findProducts, 
      $request->query->getInt('page', 1)/*page number*/, 
      20/*limit per page*/ 
     ); 

     return $this->render('StockBundle:Default:index.html.twig', 
      array('producten' => $producten)); 
    } 

Проблема страница занимает около 11-12 секунд, чтобы загрузить и потребляет 233MB оперативной памяти.

Что я могу сделать, чтобы улучшить скорость и уменьшить память?

Это моя сущность:

/** 
* Product 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="Namespace\StockBundle\Entity\ProductRepository") 
*/ 
class Product 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="naam_nl", type="string", length=255) 
    */ 
    private $naamNl; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="naam_fr", type="string", length=255) 
    */ 
    private $naamFr; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="naam_en", type="string", length=255) 
    */ 
    private $naamEn; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="productnummer", type="string", length=255) 
    */ 
    private $productnummer; 

    /** 
    * @var float 
    * 
    * @ORM\Column(name="prijs", type="float") 
    */ 
    private $prijs; 



    /** 
    * @var string 
    * 
    * @ORM\Column(name="merk", type="string", length=255) 
    */ 
    private $merk; 

    /** 
    * @ORM\OneToOne(targetEntity="Namespace\StockBundle\Entity\ProductInventory", cascade={"persist"}) 
    * @ORM\JoinColumn(name="productinventory_id", referencedColumnName="id") 
    * 
    */ 
    private $productinventory; 

Структура таблицы создается доктриной и выглядит следующим образом:

CREATE TABLE `product` (
    `id` int(11) NOT NULL, 
    `naam_nl` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `productnummer` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `prijs` double NOT NULL, 
    `merk` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `productinventory_id` int(11) DEFAULT NULL, 
    `naam_fr` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `naam_en` varchar(255) COLLATE utf8_unicode_ci NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 
+0

Это зависит не только от доктрины, можете ли вы опубликовать таблицу схем SQL? –

+0

Я добавил объект и таблицу. – yeouuu

ответ

5

Прямо сейчас вы вызываете findAll(), который будет извлекать все записи из базы данных и затем синтезировать их в объекты. Это занимает много времени, которое тратится впустую, потому что большинство из этих объектов никогда не используются снова, поскольку вы выводите только одну страницу за раз.

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

public function indexAction(Request $request) 
    { 
     $findProducts = $this->getDoctrine() 
      ->getRepository("StockBundle:Product")->createQueryBuilder("p"); 

     $paginator = $this->get('knp_paginator'); 
     $producten = $paginator->paginate(
      $findProducts, 
      $request->query->getInt('page', 1)/*page number*/, 
      20/*limit per page*/ 
     ); 

     return $this->render('StockBundle:Default:index.html.twig', 
      array('producten' => $producten)); 
    } 
+0

Вот и все, теперь моя страница занимает около 300 мс (в app_dev.php) и использует только около 19 МБ памяти. – yeouuu

0

Вы бы лучше использовать Symfony2 profiler для отладки запроса, shoud сначала add index on your fields и foreign key на поле productinventory_id.

Индекс может использовать так:

/** 
* @Entity 
* @Table(name="user",indexes={ 
*  @Index(name="email_idx", columns={"email"}) 
* }) 
*/ 
class User 
{ 
    ... 
} 

Чтобы оптимизировать этот конкретный запрос в вашем indexAction, вы могли бы сделать выбор только нужно столбца, который нужно показать в списке, а также написать запрос вместо a DQL один. , например:

// Get connection 
$conn = $entityManager->getConnection(); 

// Get table name 
$meta = $entityManager->getClassMetadata(User::class); 
$tableName = $meta->getTableName(); 

// Get random ids 
$sql = "SELECT id AS id FROM $tableName WHERE active = true ORDER BY RAND()"; 
$statement = $conn->executeQuery($sql); 
$ids = array_map(function ($element) { 
    return $element['id']; 
}, $statement->fetchAll()); 

return $ids; 

Финлей, вы должны иметь для того, чтобы инструменты кэша как apc или memcache освободить свой сервер sql.

+2

Хотя все они являются действительными стратегиями оптимизации доступа к БД, ни один из них не применим здесь. Основная проблема заключается в том, что у искателя слишком много записей. Добавление индекса вообще не поможет, и предлагается переключиться на необработанные SQL-запросы, когда вам нужно всего 20 объектов с 8 свойствами, которые просто не нужны. – Chris

+0

Я согласен с вами, ваш ответ лучше! –

Смежные вопросы