kdyby/doctrine trvání dotazů

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
jarda256
Člen | 130
+
0
-

Ahoj, chtěl bych se zeptat. Mám Entitu Event a provádím nad ní pomocí EventFacade tvorbu nové a editaci, ale přijde mi divné, že by tvorba spustila 3 queries, které by trvali 96ms a editace 4 které 110ms. Moc se v tom nevyznám, takže netuším co by mohlo způsobit, že to trvá tak dlouho (popřípadě je to dlouho nebo si to jen myslím). Předem díky za opověď.

<?php

namespace App\Model\Facades;

use App\Model\Entities\Event;
use Nette\Utils\ArrayHash;
use Nette\Object;

/**
 * @package App\Model\Facades
 */
class EventFacade extends BaseFacade
{

    /**
     * @param int|NULL $id
     * @return Event|NULL
     */
    public function getEvent($id)
    {
        return isset($id) ? $this->em->find(Event::class, $id) : NULL;
    }

    /**
     * @param ArrayHash $data
     */
    public function createEvent($data)
    {
        $element = new Event();
        $element->visible = $data->visible;
        $element->name = $data->name;
        $element->ename = $data->ename;
        $element->date = $data->date;
        $element->regInt1 = $data->regInt1;
        $element->regInt2 = $data->regInt2;
        $element->regInt3 = $data->regInt3;
        $element->regInt4 = $data->regInt4;
        $element->regInt5 = $data->regInt5;
        $element->approve = $data->approve;
        $element->regCars = $data->regCars;
        $element->optionalItems = $data->optionalItems;
        $element->note = $data->note;

        $this->em->persist($element);
        $this->em->flush();
    }

    /**
     * @return Event[]
     */
    public function getAllEvents()
    {
        $qb = $this->em->createQueryBuilder();
        $qb->addSelect('partial e.{id,visible,name,date,approve,regCars,optionalItems,note}')
            ->from(Event::class,'e')
            ->orderBy('e.date','DESC');
        $query = $qb->getQuery();
        $query->useQueryCache(true);
        $result = $query->getResult();
        return $result;
    }

    /**
     * @param int $id
     * @param ArrayHash $data
     */
    public function editEvent($id,$data)
    {
        $element = $this->getEvent($id);

        $element->visible = $data->visible;
        $element->name = $data->name;
        $element->ename = $data->ename;
        $element->date = $data->date;
        $element->regInt1 = $data->regInt1;
        $element->regInt2 = $data->regInt2;
        $element->regInt3 = $data->regInt3;
        $element->regInt4 = $data->regInt4;
        $element->regInt5 = $data->regInt5;
        $element->approve = $data->approve;
        $element->regCars = $data->regCars;
        $element->optionalItems = $data->optionalItems;
        $element->note = $data->note;

        $this->em->flush();
    }

}
<?php

namespace App\Modules\Admin\Presenters;

use Nette;
use App\Model;
use App\Forms;
use Nette\Forms\Container;
use App\Presenters\BaseAdminPresenter;
use Zend\Hydrator;

class EventPresenter extends BaseAdminPresenter
{
    /** @var Forms\CreateEventFormFactory @inject */
    public $createEventFactory;

    /** @var Forms\EditEventFormFactory @inject */
    public $editEventFactory;

    /** @var Model\Facades\EventFacade @inject */
    public $eventFacade;

    private $events;


    public function renderDefault()
    {

    }
    public function actionShow()
    {
        $this->events = $this->eventFacade->getAllEvents();
    }
    public function renderShow()
    {
        $this->template->events = $this->events;

    }
    public function actionEdit($id = NULL)
    {
        $event = $this->eventFacade->getEvent($id);
        if ($event !== NULL)
        {
            $hydrator = new Hydrator\ArraySerializable();
            $event = $hydrator->extract($event);
            $this["editEventForm"]->setDefaults($event);
        }
    }

    protected function createComponentEditEventForm()
    {
        return $this->editEventFactory->create(function () {
            $this->flashMessage("Akce byla úspěšně upravena", 'success');
            $this->redirect(':Admin:Event:show');
        });
    }

    protected function createComponentCreateEventForm()
    {
        return $this->createEventFactory->create(function () {
            $this->flashMessage("Akce byla úspěšně vytvořena", 'success');
            $this->redirect(':Admin:Event:show');
        });
    }

}
jarda256
Člen | 130
+
0
-

V případě potřeby můžu jakýkoliv soubor doplnit

F.Vesely
Člen | 369
+
0
-

Spise se podivej na ty dotazy, co to poklada. Pak zjistis, kde a proc.

jarda256
Člen | 130
+
0
-

S tím nemám problém to vidím. Jen tomu úplně nerozumím. Výpis všech eventů třeba spustí klasický select, který trvá podle tracy 3.5 ms ale v admineru trvá ani ne 1ms. Editace spustí samozřejmě načtení toho konkrétního prvku který edituji 2.8ms. Poté „START TRANSACTION“ 3.4ms pak klasický update 20.48 ms a pak „COMMIT“ a poslední 3 tedy referují k $this->em->flush(); ve funkci edit event. Nevím jestli je to tak normální tudíž i ta doba je ok nebo jestli mám tedy něco špatně.

leninzprahy
Člen | 150
+
0
-

To, že stejný dotaz jednou trvá 4 ms a jindy 1 ms, je u MySQL celkem normální, hodně záleží, jak je tam nastaveno kešování. Většinou první dotaz trvá déle, pak už to jde rychleji.

Ukládání v transakci je u Doctrine výchozí chování. Když zavoláš $em->flush();, propočítá se seznam změn a ty se v transakci synchronizují do databáze, viz http://docs.doctrine-project.org/…objects.html#…

Mě osobně ty časy připadají v pohodě, pokud bych chtěl optimalizovat, tak spíše nastavením databáze…

hitzoR
Člen | 51
+
0
-

Mi ty časy vpohodě moc nepřijdou, průměrný dotaz v mojí aplikaci trvá něco mezi 0.2 a 0.4 ms. 20 ms je strašně moc.

Jan Mikeš
Člen | 771
+
0
-

@hitzoR záleží na stroji, na databázi, na typu dotazu, zmínil, že se jedná o UPDATE, ty trvají trochu déle, obyč selecty jsou u mě také pod 1ms, u updatů je to více.

Editoval Jan Mikeš (24. 11. 2016 15:45)

leninzprahy
Člen | 150
+
0
-

hitzoR napsal(a):

Mi ty časy vpohodě moc nepřijdou, průměrný dotaz v mojí aplikaci trvá něco mezi 0.2 a 0.4 ms. 20 ms je strašně moc.

Obávám se, že nejde obecně říct, že 0.2, 2 nebo 20 ms je moc nebo málo. Záleží na hrozně moc okolnostech, od železa, přes databázový server a jeho nastavení, schéma databáze až po samotné dotazy.

Omlouvám se, ale spojení „průměrný dotaz“ je takové nic neříkající, třeba jako průměrná jízda autem, je 20 minut moc nebo málo? :)

Na druhou stranu, použití Doctrine bude vždycky pomalejší a na prostředky náročnější, než čisté SQL. Je to prostě daň za odstínění a abstrakci (podobně jako kód v php bude pomalejší než kód v C, nebo assembleru).

hitzoR
Člen | 51
+
0
-

Jan Mikeš napsal(a):

@hitzoR záleží na stroji, na databázi, na typu dotazu, zmínil, že se jedná o UPDATE, ty trvají trochu déle, obyč selecty jsou u mě také pod 1ms, u updatů je to více.

leninzprahy napsal(a):

Obávám se, že nejde obecně říct, že 0.2, 2 nebo 20 ms je moc nebo málo. Záleží na hrozně moc okolnostech, od železa, přes databázový server a jeho nastavení, schéma databáze až po samotné dotazy.

Tak je jasné, že na stroji záleží, ale na žádném ze zhruba desíti serverů, které mi prošly pod rukama za dobu, co v dělám v Nette, mi nešel ani jeden dotaz (včetně updatů a insertů do tabulek s hromadou klíčů a constraintů) nějak drasticky přes 2 ms.

leninzprahy napsal(a):

Na druhou stranu, použití Doctrine bude vždycky pomalejší a na prostředky náročnější, než čisté SQL. Je to prostě daň za odstínění a abstrakci (podobně jako kód v php bude pomalejší než kód v C, nebo assembleru).

Je jasné, že Doctrine aplikaci trochu zpomalí, ale na query execution time to nemá absolutně vliv, to je čistě v režii MySQL serveru. Jedině že by Doctrine do debug panelu nevypisovala čistý čas trvání query + režie (jako to dělá Nextras\Orm nebo NDB), ale přidávala k tomu třeba i čas namapování na entity a dalšího zpracování.

Jiří Nápravník
Člen | 710
+
0
-

Já si dovolím jednu otázku k Doctrine. Nevíte jak jde zavolat flush, ale tak aby to neběželo v transakci? Konkrétní příklad, na frontendu zapisuji otevření článku, a je mi opravdu jedno, že to neproběhne v transakci, přijde mi to i zbytečně pomalé přes to. Stačil by klasický insert mimo transakci. Jde to nějak vynutit v doctrine? Nebo musím přímo přes query nad DBAL?