我想知道为什么这个查询需要很慢(大约10到20秒),使用的三个表有500,000条记录,这是查询:
SELECT *, 'rg_egresos' AS nombre_tabla
FROM rg_detallexml DE
INNER JOIN rg_egresos EG
INNER JOIN rg_emisor EM ON DE.idContador = EG.id
AND DE.idDetalleXml = EG.idDetalleXml
AND DE.idContador = EM.idContador
AND DE.idDetalleXml = EM.idDetalleXml
WHERE DE.idContador = '14894'
AND DATE_FORMAT(dateFechaHora, '%Y-%m-%d') BETWEEN '2017-10-01'
AND '2017-10-31'
AND strTipodeComprobante = 'egreso'
AND version_xml = '3.2'
AND estado_factura = 0
AND modificado = 0;
这就是我使用EXPLAIN
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: EG
type: index_merge
possible_keys: idx_idDetallexml,idx_estado_factura,idx_modificado,idx_idContador
key: idx_idContador,idx_estado_factura,idx_modificado
key_len: 4,4,4
ref: NULL
rows: 2111
Extra: Using intersect(idx_idContador,idx_estado_factura,idx_modificado); Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: DE
type: eq_ref
possible_keys: PRIMARY,idx_strTipodeComprobante,idx_idContador,idx_version_xml
key: PRIMARY
key_len: 4
ref: db_pwf.EG.idDetalleXml
rows: 1
Extra: Using where
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: EM
type: ref
possible_keys: idx_idContador,idx_idDetallexml
key: idx_idDetallexml
key_len: 4
ref: db_pwf.DE.idDetalleXml
rows: 1
Extra: Using where
你能看到改进查询的方法吗?我有其他查询使用更大的表,它们更快,所有必填字段都有索引,谢谢。
表rg_detallexml:
+---------------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------------+--------------+------+-----+---------+----------------+
| idDetalleXml | int(10) | NO | PRI | NULL | auto_increment |
| UUID | varchar(50) | NO | MUL | NULL | |
| dateFechaSubida | varchar(7) | YES | | NULL | |
| idContador | int(10) | NO | MUL | NULL | |
| dateFechaHora | datetime | YES | MUL | NULL | |
| dateFechaHoraCertificacion | datetime | YES | | NULL | |
| dateFechaPago | datetime | YES | | NULL | |
| intFolio | int(10) | YES | | NULL | |
| strSerie | varchar(2) | YES | | A | |
| doubleDescuento | double | YES | | NULL | |
| doubleTotal | double | YES | | NULL | |
| doubleSubtotal | double | YES | | NULL | |
| duobleTotalImpuestosTrasladados | double | YES | | NULL | |
| doubleTotalImpuestosRetenidos | double | YES | | NULL | |
| doubleTotalRetencionesLocales | double | YES | | NULL | |
| doubleTotalTrasladosLocales | double | YES | | NULL | |
| strTipodeComprobante | varchar(15) | YES | MUL | NULL | |
| strMetodoDePago | varchar(150) | YES | | NULL | |
| strFormaDePago | varchar(150) | YES | | NULL | |
| strMoneda | varchar(10) | YES | | NULL | |
| tipoCambio | double | NO | | NULL | |
| strLugarExpedicion | varchar(150) | YES | | NULL | |
| DIOT | int(1) | YES | | 0 | |
| version_xml | varchar(10) | NO | MUL | NULL | |
+---------------------------------+--------------+------+-----+---------+----------------+
表rg_egresos:
+---------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+--------------+------+-----+---------+----------------+
| id_egreso | int(11) | NO | PRI | NULL | auto_increment |
| id | int(11) | NO | MUL | NULL | |
| idDetalleXml | int(10) | NO | MUL | NULL | |
| idCatalogo | int(19) | NO | MUL | NULL | |
| tipoCuenta | int(11) | NO | MUL | NULL | |
| intRubro | int(1) | NO | | NULL | |
| RFC | varchar(20) | NO | MUL | NULL | |
| compra_gastos_0_porciento | float | NO | MUL | NULL | |
| deducible | int(1) | NO | | NULL | |
| compra_gastos_exentos | float | NO | | NULL | |
| no_deducibles | float | NO | | NULL | |
| estado_factura | int(11) | NO | MUL | NULL | |
| fecha | date | NO | MUL | NULL | |
| total_xml | double | NO | | NULL | |
| subtotal_xml | double | NO | | NULL | |
| iva_xml | double | NO | | NULL | |
| total_impuestos | double | NO | | NULL | |
| abonado | double | NO | | NULL | |
| subtotal | double | NO | | NULL | |
| iva | double | NO | | NULL | |
| pendiente | double | NO | | NULL | |
| subtotal_sin_iva | double | NO | | NULL | |
| acreditable | int(1) | NO | MUL | 0 | |
| fecha_operacion | datetime | NO | MUL | NULL | |
| modificado | int(1) | NO | MUL | NULL | |
| UUID | varchar(50) | NO | MUL | NULL | |
| IEPS | double | NO | | NULL | |
| retencion_iva | double | NO | | NULL | |
| retencion_isr | double | NO | | NULL | |
| imp_local | double | NO | | 0 | |
| enviado_a | int(11) | NO | MUL | NULL | |
| enviado_al_iva | int(1) | NO | | NULL | |
| EsNomina | int(1) | NO | MUL | 0 | |
| dateFechaPago | date | NO | MUL | NULL | |
| nota_credito | int(1) | NO | MUL | NULL | |
| extranjero | int(1) | NO | MUL | NULL | |
| pago_banco | int(1) | NO | MUL | NULL | |
| idBanco_Pago | int(20) | NO | MUL | NULL | |
| movimientoPago | int(10) | NO | | NULL | |
| saldo_banco | varchar(50) | NO | | NULL | |
| tipo_pago | int(1) | NO | | 0 | |
| responsable | varchar(100) | NO | | NULL | |
+---------------------------+--------------+------+-----+---------+----------------+
表rg_emisor:
+-----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+----------------+
| idEmisor | int(10) | NO | PRI | NULL | auto_increment |
| idDetalleXml | int(10) | NO | MUL | NULL | |
| idContador | int(10) | NO | MUL | NULL | |
| strRFC | varchar(13) | NO | | NULL | |
| strNombreEmisor | varchar(200) | YES | | NULL | |
| strRegimen | varchar(250) | YES | | NULL | |
| strPais | varchar(40) | YES | | MX | |
| strEstado | varchar(50) | YES | | NULL | |
| intCP | int(5) | YES | | NULL | |
| strMunicipio | varchar(250) | YES | | NULL | |
| strLocalidad | varchar(250) | YES | | NULL | |
| strColonia | varchar(250) | YES | | NULL | |
| intNumExt | int(10) | YES | | NULL | |
| intNumInt | int(10) | YES | | NULL | |
| strCalle | varchar(250) | YES | | NULL | |
| regimenFiscal | varchar(20) | YES | | NULL | |
+-----------------+--------------+------+-----+---------+----------------+
答案 0 :(得分:3)
现在您已经显示了表格,我们发现rg_egresos.id
不是表格的ID。因此,表中的一个概念可以有多个记录。让我们更仔细地查看表格和查询:
所有表格都包含一个contador ID和一个DetalleXml ID。你想在这两个领域加入他们。所以你从rg_detallexml
开始并获取contador的所有记录。使用找到的idDetalleXml
,您可以搜索rg_egresos
和rg_emisors
。
这有点奇怪。首先,rg_detallexml
显然与一个概念相关联,但在其他表格中,rg_detallexml
可以与另一个概念相关联。嗯,这可能是可能的(可能是某种关系)。但是,对于rg_egresos
/ contador,有五个rg_emisors
条记录和四条rg_detallexml
条记录,您需要选择30条记录,因为您要将rg_egresos
条记录与rg_emisors
组合在一起与真正无关的记录。
无论如何:你想快速找到rg_detallexml
。
create index idx_de on rg_detallexml(idcontador, strtipodecomprobante, version_xml,
datefechahora, iddetallexml);
然后你找rg_egresos
:
create index idx_eg on rg_egresos(id, iddetallexml, estado_factura, modificad);
最后你要找rg_emisor
:
create index idx_em on rg_emisor(idcontador, iddetallexml);
由于列存在于所有表中,我们当然可以按任何顺序浏览它们。从rg_detallexml
开始似乎也是最自然和最具限制性的,但这不一定是最好的。所以你可能想要为DBMS提供另一个索引:
create index idx_eg2 on rg_egresos(id, estado_factura, modificad, iddetallexml);
这将允许DBMS首先在此表中查找contador的记录,并使用添加的条件在此处查找相关的iddetallexml
。
答案 1 :(得分:1)
我看到的最大问题是这一部分:
library(purrr)
ParsedFile %>% map(~map_df(., ~trimws(.)))
dateFechaHora是一个日期时间字段吗?为什么要将datetime字段转换为字符串(DATE_FORMAT)?即使你在dateFechaHora字段上有索引,它也不会被使用。
我建议您改用此代码:
DATE_FORMAT(dateFechaHora, '%Y-%m-%d') BETWEEN '2017-10-01' AND '2017-10-31'
是的,第二天它就不会被包括在内。
所以你的查询可能如下所示:
and DateFechaHora >= '2017-10-01' and DateFechaHora < '2017-11-01'
^^^^^^^^^^
答案 2 :(得分:1)
我在其他回复中看到两个部分答案。让我们把它们绑在一起。
更改
AND DATE_FORMAT(dateFechaHora, '%Y-%m-%d') BETWEEN '2017-10-01'
AND '2017-10-31'
到
AND DE.dateFechaHora >= '2017-10-01'
AND DE.dateFechaHora < '2017-10-01' + INTERVAL 1 MONTH
和
如果DE是一个很好的起点:
DE: INDEX(idContador, strTipodeComprobante, version_xml, dateFechaHora)
-- date last; others in any order
如果EG是一个更好的起点:
EG: INDEX(estado_factura, modificado, id) -- in any order
DE: INDEX(idContador, idDetalleXml,
strTipodeComprobante, version_xml, dateFechaHora)
也有
EM: INDEX(idContador, idDetalleXml) -- in either order
“使用intersect”几乎总是一个线索,你应该有一个复合索引而不是单独的索引。 (单独的索引可能对其他查询有用。)
(即添加所有这些索引,然后让优化器决定。)
请使用SHOW CREATE TABLE
,而不是描述性较低的DESCRIBE
。
你真的需要SELECT *
吗?
查询后,我的建议:
SELECT DE.*,
EG.*,
EM.*,
'rg_egresos' AS nombre_tabla
FROM rg_detallexml DE
INNER JOIN rg_egresos EG
ON DE.idContador = EG.id
AND DE.idDetalleXml = EG.idDetalleXml
INNER JOIN rg_emisor EM
ON DE.idContador = EM.idContador
AND DE.idDetalleXml = EM.idDetalleXml
WHERE DE.idContador = '14894'
AND DE.dateFechaHora >= '2017-10-01'
AND DE.dateFechaHora < '2017-10-01' + INTERVAL 1 MONTH
AND DE.strTipodeComprobante = 'egreso'
AND DE.version_xml = '3.2'
AND EG.estado_factura = 0
AND EG.modificado = 0;