Meus logs mostram que a consulta explicada aqui levou 352,19 segundos (e tempos semelhantes para outras consultas semelhantes em que contact_id
e execute_at
eram diferentes).
EXPLAIN SELECT
*
FROM
`automations`
WHERE
(`contact_id` = 22638
AND `job_class_name` = 'App\Jobs\MyJob'
AND `execute_at` = '2018-12-15 16:43:00')
AND `automations`.`deleted_at` IS NULL
LIMIT 1
Resultado de EXPLIQUE:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|----|-------------|-------------|------------|------|--------------------------------|--------------------------------|---------|-------------------------|------|----------|-----------------------|
| 1 | SIMPLE | automations | NULL | ref | cId_job_executeAt_delAt_unique | cId_job_executeAt_delAt_unique | 780 | const,const,const,const | 1 | 100.00 | Using index condition |
Eu sou inexperiente em otimizar o MySql, mas meu palpite é que o Explain parece ótimo, certo?
Por que diabos consultas como essa levariam mais de 350 segundos? Como posso diagnosticar e corrigir?
PS Isso está relacionado ao E_WARNING: Error while sending STMT_PREPARE packet. PID=*
erro que vejo com frequência.
CREATE TABLE `automations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`contact_id` int(10) unsigned NOT NULL,
`job_class_name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`execute_at` datetime NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `cId_job_executeAt_delAt_unique` (`contact_id`,`job_class_name`,`execute_at`,`deleted_at`),
CONSTRAINT `automations_contact_id_foreign` FOREIGN KEY (`contact_id`) REFERENCES `contacts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1519 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
O índice ideal para esta consulta seria um índice composto com 4 colunas, em qualquer ordem:
E, dependendo da ordem que você escolher, você pode se livrar de uma das CHAVES existentes.
Cuidado com as barras invertidas.
'App\Jobs\MyJob'
pode ser tratado comoApp[LF]obs[CR]yJob
ouAppJobsMyJob
.352 segundos é realmente irracional. Talvez algo mais estivesse acontecendo e bloqueando o acesso às linhas e/ou à tabela?(Os 352s eram falsos.)"Usando condição de índice" não é o mesmo que "Usando índice". Este último indica um "índice de cobertura", o que não é prático para esta consulta e tabela.
Minhas consultas que eu achava que levavam 352 segundos na verdade levavam apenas 0,352 segundos! ?♂️
https://laravel.io/forum/03-04-2014-what-time-format-does-dbgetquerylog-return me mostrou que o Laravel
DB::getQueryLog()
mostra "tempo" como milissegundos (microssegundos multiplicado por 1000), não segundos.Que erro embaraçoso (pobre suposição). Então, preciso editar minha pergunta de recompensa de 500 pontos: https://stackoverflow.com/questions/53469793/e-warning-error-while-sending-stmt-prepare-packet-pid/54374937?noredirect=1#comment95579631_53469793