Velka „prasárna“ ve výběru dat z DB

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

Ahoj kluci,

mám takový dotaz, je tohle hodně velká „prasárna“ na dotazy do DB??? (podle mě jo)

Vemte, že se může vytáhnout třeba 1 000 000 adres …

A dále ještě … asi jsem mimoň, ale proč mě to zase pošle jenom na první adresu nalezenou? Myslel jsem, že když je to ve foreach, pošle to na všechny …

Děkuji

protected function execute(InputInterface $input, OutputInterface $output) {

        try {
            // Nastaveni modelu
            $cron = $this->cron->findAll();
            $emailySeznamy = $this->emailySeznamy->findAll();
            $emaily = $this->emaily->findAll();
            $kampane = $this->kampane->findAll();
            $seznam = $this->seznamy->findAll();

            // Nastaveni datetime
            $datetime = new Nette\Utils\DateTime();

            // Projeti cronu
            foreach ($cron as $c) {
                if ($c->start->format('Y-m-d H:i') === $datetime->format('Y-m-d H:i')) {
                    foreach ($seznam->where('id', $c->seznamy_id) as $s) {
                        foreach ($emailySeznamy->where('seznamy_id', $s->id) as $es) {
                            foreach ($emaily->where('id', $es->emaily_id) as $e) {
                                try {
                                    $mail = new Message();
                                    $mail->setFrom('info@jirickajakub.cz');
                                    $mail->addTo($e->email);
                                    $mail->setSubject('Pokus cron emailu');
                                    $mail->setBody('ANO! :) <br> cas:' . $e->email . $datetime . 'cron id:' . $c->id . 'cron cas:' . $c->start);

                                    $mailer = new Nette\Mail\SendmailMailer();
                                    $mailer->send($mail);

                                    sleep(1);
                                } catch (Nette\Mail\SmtpException $ex) {
                                    Debugger::log($ex, Debugger::ERROR);
                                    throw $ex;
                                }
                            }
                        }
                    }
                }
            }

            $output->writeLn(new Nette\Utils\DateTime() . '<info>[OK] - cron</info>');
            return 0;
        } catch (\Exception $exc) {
            $output->writeLn(new Nette\Utils\DateTime() . '<error>cron - ' . $exc->getMessage() . '</error>');
            return 1;
        }
    }
Filip Klimeš
Nette Blogger | 156
+
0
-

Já osobně bych místo foreachování vybral data nějakým joinem a iteroval už pouze přes ty maily. Tedy postavit dotaz cca jako:

SELECT emaily.email, crony.id, crony.start, ... FROM crony
INNER JOIN seznamy ON seznamy.id = crony.seznamy_id
INNER JOIN emailySeznamy ON emailySeznamy.seznamy_id = seznamy.id
INNER JOIN emaily ON  emaily.id = emailySeznamy.emaily_id
WHERE crony.start LIKE :datum

a pak už jen:

$now = new DateTime();
$emaily = $this->emaily->findByCronStart($now);
foreach($emaily as $email) {
	...
}

Editoval Filip Klimeš (2. 3. 2015 19:14)

wicked
Člen | 290
+
0
-

Tak jsem to nějak zkusil …

Udělal jsem si toto v modelu:

public function runCron($datum) {
        return $this->database->query('SELECT emaily.*, cron.*, cron.*, kampane.* FROM cron
                                        INNER JOIN seznamy ON seznamy.id = cron.seznamy_id
                                        INNER JOIN emaily_seznamy ON emaily_seznamy.seznamy_id = 				   seznamy.id
                                        INNER JOIN emaily ON  emaily.id = emaily_seznamy.emaily_id
                                        INNER JOIN kampane ON kampane.id = cron.kampane_id where cron.start LIKE ?', $datum);
    }

V presenteru jednoduchy dump:
kde cas odpovida zaznamu v DB …

public function beforeRender() {
        $cron = $this->cron->runCron('2015-03-02 18:56:00');
        dump($cron);
    }

Coz me vygeneruje takovyto SQL dotaz (debugg bar)

SELECT emaily.*, cron.*, cron.*, kampane.*
FROM cron
INNER JOIN seznamy ON seznamy.id = cron.seznamy_id
INNER JOIN emaily_seznamy ON emaily_seznamy.seznamy_id = seznamy.id
INNER JOIN emaily ON emaily.id = emaily_seznamy.emaily_id
INNER JOIN kampane ON kampane.id = cron.kampane_id
where cron.start LIKE '2015-03-02 18:56:00'

Ale v dumpu mám:

Nette\Database\ResultSet #9f3d
connection private => Nette\Database\Connection #bd57
supplementalDriver private => Nette\Database\Drivers\MySqlDriver #9e47
connection private => Nette\Database\Connection #bd57
pdoStatement private => PDOStatement #65b1
queryString => "SELECT emaily.*, cron.*, cron.*, kampane.* FROM cron
INNER JOIN seznamy ON seznamy.id = cron.seznamy_id
INNER JOIN emaily_seznamy ON emaily_seznamy. ... " (329)
result private => NULL
resultKey private => -1
results private => NULL
time private => 0.00014615058898926
queryString private => "SELECT emaily.*, cron.*, cron.*, kampane.* FROM cron
INNER JOIN seznamy ON seznamy.id = cron.seznamy_id
INNER JOIN emaily_seznamy ON emaily_seznamy. ... " (329)
params private => array ()
types private => NULL

Takže žádné data … (Nebo jsem slepý?)

Když to projedu forach, tak to na mě řve:
Found duplicate columns in database result set

Nápad/rada?

wicked
Člen | 290
+
0
-

Nikoho nic nenapada?

looky
Člen | 99
+
0
-

Proč tam máš dvakrát cron.*?

wicked
Člen | 290
+
0
-

Tohle byl překlik … ale děkuji za upozornění :)

Každopádně to pořád ale dělá to same … :-(

studna
Člen | 181
+
+1
-

Ta hláška Found duplicate columns in database result set přesně říká, co je špatně. Nepoužívej „hvězdičku“, ale vyber pouze sloupce, které opravdu potřebuješ. A pokud potřebuješ vybrat více stejnojmenných sloupců, tak si je aliasuj.

$db->query('SELECT emaily.id, cron.id cron_id, ...');

Editoval studna (7. 3. 2015 16:10)

wicked
Člen | 290
+
0
-

Jsi úžasný … děkuji!

V Admineru i PhpMyAdmin to fungovalo, a tady ne, tak mě ty * nedošli :)

DĚKUJI! :-)