当我仅在一个表中选择查询时,我们使用索引得到了响应,但是当使用join statemnt时,在查询中,mysql对表进行了完全扫描?
第一个查询
select *
from t_deposit_trx
where remit_tx_id = '3a33ff14-8d31-45d0-b64f-8a251c4b19a5'
1个简单的t_deposit_trx ref t_deposit_trx_remit_tx_id_index
t_deposit_trx_remit_tx_id_index 110 const 1使用索引条件
第二次查询
select tx_id
from t_settle_trx
where report_date >= '2019-03-01'
and report_date <= '2019-03-16'
and tx_type = 'CANCEL'
1个简单的t_settle_trx范围t_settle_trx_report_date_tx_type_index t_settle_trx_report_date_tx_type_index 196 5263使用索引条件
2查询操作良好。 使用索引和速度是好的。
但是将两个表连接在一起,速度非常慢。
select * from t_deposit_trx
force index (t_deposit_trx_remit_tx_id_index)
where remit_tx_id in (
select tx_id
from t_settle_trx
where report_date >= '2019-03-01'
and report_date <= '2019-03-02'
and tx_type = 'CANCEL'
)
1个主要t_deposit_trx ALL 55724
1主要t_settle_trx范围t_settle_trx_report_date_tx_type_index t_settle_trx_report_date_tx_type_index 196299使用索引条件;在哪里使用FirstMatch(t_deposit_trx);使用连接缓冲区(平面,BNL连接)
我们可以看到以上结果。 t_settle_trx使用范围扫描并获取tx_id,接下来我希望查询使用索引 “ t_settle_trx_report_date_tx_type_index” 但是它使用完整扫描。
我不知道为什么?
答案 0 :(得分:1)
查询2并非最佳选择。转过索引:
INDEX(tx_type, report_date)
也就是说,不管基数如何,都将使用=
测试的列放在 之上。
IN ( SELECT ... )
不是 a JOIN
。 (在较新的版本中,它可能可能会转换为JOIN
。)
尝试一下:
SELECT d.*
FROM t_settle_trx AS s
JOIN t_deposit_trx AS d ON s.tx_id = d.remit_tx_id
WHERE s.tx_type = 'CANCEL'
AND s.report_date >= '2019-03-01'
AND s.report_date < '2019-03-01' + INTERVAL 2 DAY
s: INDEX(tx_type, report_date, tx_id)
d: INDEX(remit_tx_id)
从带有SELECT
子句的表开始,以JOIN
开头的WHERE
来思考。
(注意:我排列了表格和where-子句的顺序,以便您可以看到Optimizer的想法。表格的顺序和where-子句的顺序无关; Optimizer会根据需要重新排列)
我的配方应该
全表扫描不一定是件坏事。如果仍然要触摸表的 most ,那么简单地扫描表而不在索引的BTree和数据的BTree之间跳动实际上会更快。 (您的特定案例还有其他缺陷;我专注于这些缺陷。)
INDEX(tx_type, report_date, tx_id)
是“覆盖”的,因为查询所需的所有列都在一个索引中找到。 “覆盖”为您带来了一点额外的性能提升。在EXPLAIN
中用Using index
(不是Using index condition
)表示。
对于tx_seq,这可能是最佳选择:
INDEX(tx_type, report_date, tx_seq)
答案 1 :(得分:0)
我希望这不会比您的第一个查询慢:
SELECT t1.* FROM t_deposit_trx t1
INNER JOIN t_settle_trx t2
ON t1.remit_tx_id=t2.tx_id
WHERE t2.report_date >= '2019-03-01'
AND t2.report_date <= '2019-03-02'
AND t2.tx_type='CANCEL';
答案 2 :(得分:0)
人.. 谢谢您对我的问题的关注。
在暂存环境和生产环境中,以上两个表具有相同的索引结构。 并使用galera群集。
我真正想知道的是为什么他们使用不同的“执行计划”? 特别是在生产环境中,JOIN查询非常慢。
我昨天要做的是..
select * from t_deposit_trx
where remit_tx_id in (
select tx_id
from t_settle_trx
where report_date >= '2019-03-01'
and report_date <= '2019-03-02'
and tx_type = 'CANCEL'
)
我对该查询的更改有点像
select * from t_deposit_trx
where tx_seq in (
select tx_seq
from t_settle_trx
where report_date >= '2019-03-01'
and report_date <= '2019-03-02'
and tx_type = 'CANCEL'
)
,然后是第一个t_settle_trx“范围扫描”,第二个t_deposit_trx“索引扫描”。 但是两个tx_seq值是不同的值。它没有任何关系。 这只是测试他们在加入查询时是否可以使用索引。
你知道我的意思吗? 这意味着他们可以在加入时使用索引。
那么是否存在任何环境变量问题或密钥长度限制或其他问题?
谢谢你读我。