我有一个带有订单的商店系统,该系统具有订单及其物料的状态。我有这六个表:
订单(pedido
)。
订购商品(pedido_item
)。
订单状态(status_pedido
)。
订单商品状态(status
)。
订单状态日志(pedido_status_pedido
)。
订单商品状态日志(pedido_item_status
)。
因此,当我必须从订单更新状态时,我在pedido_status_pedido
上插入新行,并更新表status_pedido_id
上的pedido
。物品也一样。
一个订单状态与许多项目状态相关联,例如,订单状态“待处理”与项目状态“正在等待文件”,“有错误的文件”和“已批准文件”相关。
例如,当前订单状态基于其当前商品状态,例如最“延迟”的状态,而“成品错误”项目后面是“错误文件”。为此,在订单和商品状态上都有列列。
因此,如果我的订单上有3个项目,且状态为“有错误的文件”,“生产中”,“生产完成”,则订单状态为“待处理”,因为这是该订单的对应订单状态项状态“文件错误”,该状态更远。
问题是当我必须更新特定的订单状态时。我提出了一个非常复杂的查询,我需要SET SQL_BIG_SELECTS=1
使其运行。显然,查询是如此之慢,以至于使我的整个网站都很慢(每10分钟调用一次,以获取大量订单)
这是我的查询,解释如下:
INSERT INTO pedido_status_pedido (pedido_id, status_pedido_id) VALUES ({$this->pedido_id}, ( --Insert into order status log the id, and the status id
SELECT sp.status_pedido_id FROM `status` s --Subquery for the order status id, get it from the relationship inside the item status
LEFT JOIN status_pedido sp ON sp.status_pedido_id = s.status_pedido_id
WHERE s.status_id = ( --Subquery for the further behind item status
SELECT s.status_id FROM pedido_item_status p1
LEFT JOIN `status` s ON s.status_id = p1.status_id
LEFT JOIN pedido_item ON pedido_item.pedido_item_id = p1.pedido_item_id
INNER JOIN ( --Get the LATEST status of each item and compare
SELECT MAX( si.sta_ordem ) AS maxordem, pedido_item_id FROM pedido_item_status pi
LEFT JOIN status si ON pi.status_id = si.status_id
WHERE pi.excluido IS NULL AND pi.pedido_id = {$this->pedido_id}
GROUP BY pi.pedido_item_id
) p2 ON ( s.sta_ordem = p2.maxordem ) AND p1.excluido IS NULL AND p1.pedido_item_id = p2.pedido_item_id
WHERE p1.pedido_id = {$this->pedido_id}
ORDER BY s.sta_ordem ASC
LIMIT 1
)
)
这是表的定义(对不起,它有点大):
CREATE TABLE `pedido` (
`pedido_id` int(11) NOT NULL AUTO_INCREMENT,
`cliente_id` int(11) NULL DEFAULT NULL,
`forma_envio_id` int(11) NULL DEFAULT NULL,
`balcao_retirada_id` int(11) NULL DEFAULT NULL,
`ped_responsavel_retirada` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`ped_codigo_rastreio` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`ped_prazo_entrega` int(11) NULL DEFAULT NULL,
`ped_prazo_producao` int(11) NULL DEFAULT 0,
`ped_data` datetime(0) NULL DEFAULT '0000-00-00 00:00:00',
`ped_data_producao` date NULL DEFAULT NULL,
`ped_data_entrega` date NULL DEFAULT NULL,
`ped_notificado` char(1) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT 'N',
`ped_transacao_pagarme` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`ped_cmd` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT '',
`ped_data_confirmacao_pagamento` datetime(0) NULL DEFAULT NULL,
`forma_pagamento_id` int(11) NULL DEFAULT NULL,
`ped_vencimento_boleto` date NULL DEFAULT NULL,
`ped_comprovante` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`ped_pago` char(1) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT 'N',
`status_id` int(11) NOT NULL DEFAULT 0,
`status_pedido_id` int(11) NOT NULL DEFAULT 0,
`ped_valor_adicionais` decimal(10, 2) NULL DEFAULT NULL,
`ped_valor_frete` decimal(10, 2) NULL DEFAULT NULL,
`ped_valor_produtos` decimal(10, 2) NULL DEFAULT 0.00,
`ped_valor_desconto` decimal(10, 2) NULL DEFAULT 0.00,
`ped_valor_total` decimal(10, 2) NULL DEFAULT 0.00,
`excluido` datetime(0) NULL DEFAULT NULL,
`cadastrado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP,
`atualizado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`pedido_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15876 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
CREATE TABLE `pedido_item` (
`pedido_item_id` int(11) NOT NULL AUTO_INCREMENT,
`pedido_id` int(11) NULL DEFAULT NULL,
`pei_indice` int(11) NULL DEFAULT NULL,
`produto_id` int(11) NULL DEFAULT NULL,
`produto_variacao_id` int(11) NULL DEFAULT NULL,
`produto_preco_id` int(11) NULL DEFAULT NULL,
`tipo_arquivo_id` int(11) NULL DEFAULT NULL,
`pei_arquivo` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`pei_arquivo_nome` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`pei_nome` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`pei_quantidade` int(11) NULL DEFAULT NULL,
`pei_valor_unitario` decimal(10, 2) NULL DEFAULT NULL,
`pei_valor_total` decimal(10, 2) NULL DEFAULT NULL,
`pei_valor_frete` decimal(10, 2) NULL DEFAULT NULL,
`pei_codigo_preco` int(11) NULL DEFAULT NULL,
`pei_codigo_interno` varchar(40) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`status_id` int(11) NOT NULL DEFAULT 0,
`excluido` timestamp(0) NULL DEFAULT NULL,
`cadastrado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP,
`atualizado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
`pei_producao_finalizada` char(1) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT 'N',
`pei_arquivo_erro` char(1) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`pedido_item_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 17528 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
CREATE TABLE `pedido_item_status` (
`pedido_item_status_id` int(11) NOT NULL AUTO_INCREMENT,
`pedido_id` int(11) NOT NULL,
`pedido_item_id` int(11) NOT NULL,
`status_id` int(11) NOT NULL,
`pis_texto` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL,
`pis_notificar_cliente` char(1) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT 'S',
`excluido` datetime(0) NULL DEFAULT NULL,
`cadastrado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP,
`atualizado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`pedido_item_status_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 35743 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
CREATE TABLE `pedido_status_pedido` (
`pedido_status_pedido_id` int(11) NOT NULL AUTO_INCREMENT,
`pedido_id` int(11) NULL DEFAULT NULL,
`status_pedido_id` int(11) NULL DEFAULT NULL,
`psp_notificar_cliente` char(1) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT 'S',
`psp_texto` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL,
`excluido` timestamp(0) NULL DEFAULT NULL,
`cadastrado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP,
`atualizado` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`pedido_status_pedido_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 38216 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
CREATE TABLE `status` (
`status_id` int(11) NOT NULL AUTO_INCREMENT,
`sta_nome` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`sta_observacao` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`sta_ordem` int(11) NULL DEFAULT NULL,
`status_pedido_id` int(11) NULL DEFAULT NULL,
`excluido` datetime(0) NULL DEFAULT NULL,
`cadastrado` datetime(0) NULL DEFAULT NULL,
`atualizado` datetime(0) NULL DEFAULT NULL,
`sta_cor` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`sta_icon` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`sta_alert` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`status_id`) USING BTREE,
INDEX `idx_1`(`excluido`, `status_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
INSERT INTO `status` VALUES (1, 'Aguardando pagamento', NULL, 1, 1, NULL, NULL, NULL, '#CACACA', 'fa-clock-o', 'alert-warning');
INSERT INTO `status` VALUES (2, 'Aguardando arquivo', NULL, 2, 2, NULL, NULL, NULL, '#FAC08C', 'fa-file-image-o', 'alert-warning');
INSERT INTO `status` VALUES (3, 'Arquivo em análise', NULL, 4, 2, NULL, NULL, NULL, '#8CBCFA', 'fa-spinner', 'alert-info');
INSERT INTO `status` VALUES (4, 'Produção finalizada', NULL, 9, 4, NULL, NULL, NULL, '#DCBCA5', 'check-square-o', 'alert-info');
INSERT INTO `status` VALUES (5, 'Arquivo com erro', NULL, 5, 2, NULL, NULL, NULL, '#FF8C8C', 'fa-exclamation-circle', 'alert-danger');
INSERT INTO `status` VALUES (6, 'Em produção', NULL, 7, 3, NULL, NULL, NULL, '#8CBCFA', 'fa-cogs', 'alert-info');
INSERT INTO `status` VALUES (7, 'Em transporte', NULL, 11, 5, NULL, NULL, NULL, '#DCA5A5', 'fa-truck', 'alert-info');
INSERT INTO `status` VALUES (8, 'Entregue', NULL, 12, 6, NULL, NULL, NULL, '#5CCE90', 'fa-check-circle-o', 'alert-success');
INSERT INTO `status` VALUES (9, 'Cancelado', NULL, 13, 7, NULL, NULL, NULL, '#FF7979', 'fa-times-circle-o', 'alert-danger');
INSERT INTO `status` VALUES (10, 'Pronto para retirada', NULL, 10, 4, NULL, NULL, NULL, '#FFD24D', 'fa-check-circle-o', 'alert-info');
INSERT INTO `status` VALUES (11, 'Produto com defeito', NULL, 8, 3, NULL, NULL, NULL, '#FF8C8C', 'fa-exclamation-circle', 'alert-danger');
INSERT INTO `status` VALUES (12, 'Arquivo aprovado', NULL, 6, 20, NULL, NULL, NULL, '#C0ED85', 'fa-check-circle-o', 'alert-info');
INSERT INTO `status` VALUES (13, 'Em Espera', NULL, 3, 1, NULL, NULL, NULL, '#8CBCFA', 'fa-spinner', 'alert-info');
CREATE TABLE `status_pedido` (
`status_pedido_id` int(11) NOT NULL AUTO_INCREMENT,
`stp_nome` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`stp_observacao` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`stp_ordem` int(11) NULL DEFAULT NULL,
`excluido` datetime(0) NULL DEFAULT NULL,
`cadastrado` datetime(0) NULL DEFAULT NULL,
`atualizado` datetime(0) NULL DEFAULT NULL,
`stp_cor` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`stp_icon` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`stp_alert` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`status_pedido_id`) USING BTREE,
INDEX `idx_1`(`excluido`, `status_pedido_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
INSERT INTO `status_pedido` VALUES (1, 'Aguardando pagamento', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (2, 'Pendente', NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (3, 'Em produção', NULL, 4, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (4, 'Pronto', NULL, 5, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (5, 'Em transporte', NULL, 6, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (6, 'Entregue', NULL, 7, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (7, 'Cancelado', NULL, 8, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO `status_pedido` VALUES (20, 'Aprovado', NULL, 3, NULL, NULL, NULL, NULL, NULL, NULL);
查询本身可以正常工作,但是我需要一种使其更快的方法。如果我将其分解为较小的查询,可能会更好一些?还是我使用了太多不必要的数据?
编辑:
在回答之后,新查询现在看起来像这样:
SELECT s.status_pedido_id AS status_pedido_atual, p.status_pedido_id AS status_pedido_anterior FROM `status` s
LEFT JOIN pedido p ON p.pedido_id = {$_POST['pedido_id']}
WHERE s.sta_ordem =
(
SELECT MAX( si.sta_ordem ) AS max_ordem
FROM pedido_item_status pis
LEFT JOIN `status` si ON si.status_id = pis.status_id
WHERE pis.pedido_id = {$_POST['pedido_id']}
AND pis.excluido IS NULL
GROUP BY pis.pedido_item_id
ORDER BY max_ordem ASC
LIMIT 1
)
然后,我使用结果在另一个查询中插入订单状态日志。我快多了。我解决的整个过程的逻辑还存在其他问题。
答案 0 :(得分:0)
好吧,我的猜测是运行EXPLAIN ...
并为您的INSERT ...
查询运行
+---+----------+----------------------+--+--------+-------------+-------------+--+--+---+--------+----------------------------------------------+
| 1 | INSERT | pedido_status_pedido | | ALL | | | | | | | |
+---+----------+----------------------+--+--------+-------------+-------------+--+--+---+--------+----------------------------------------------+
| 2 | SUBQUERY | | | | | | | | | | no matching row in const table |
| 3 | SUBQUERY | p1 | | ALL | | | | | 1 | 100.00 | Using where; Using temporary; Using filesort |
| 3 | SUBQUERY | s | | eq_ref | PRIMARY | PRIMARY | | | 1 | 100.00 | Using where |
| 3 | SUBQUERY | pedido_item | | eq_ref | PRIMARY | PRIMARY | | | 1 | 100.00 | Using index |
| 3 | SUBQUERY | <derived4> | | ref | <auto_key0> | <auto_key0> | | | 2 | 100.00 | Using index |
| 4 | DERIVED | pi | | ALL | | | | | 1 | 100.00 | Using where; Using temporary; Using filesort |
| 4 | DERIVED | si | | eq_ref | PRIMARY | PRIMARY | | | 1 | 100.00 | |
+---+----------+----------------------+--+--------+-------------+-------------+--+--+---+--------+----------------------------------------------+
我处理了所有数据,发现(可能)您有7个子查询中的3个,没有可能的搜索关键字
我将开始分解您的查询,并用EXPLAIN
检查它们是否存在瓶颈。
否则,我将运行此查询(当然,我已经在表中填充了一些虚假数据),并且执行了0.016秒。真讨厌这就是为什么后端代码和/或数据量/服务器功能的另一个猜测。
所以,最后:
EXPLAIN
MAX( si.sta_ordem )
,而无需为每个查询重新计算它。如果您一直在运行服务-您可以将临时表用于缓存。