为什么要进行MySQL JOIN查询-完全SCAN不使用索引

时间:2019-04-04 01:48:16

标签: mysql indexing mariadb query-optimization

当我仅在一个表中选择查询时,我们使用索引得到了响应,但是当使用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” 但是它使用完整扫描。

我不知道为什么?

3 个答案:

答案 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会根据需要重新排列)

我的配方应该

  • 充分利用两个表上的索引。
  • 避免全表扫描
  • 在其查看的 first 表上进行所有过滤

全表扫描不一定是件坏事。如果仍然要触摸表的 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值是不同的值。它没有任何关系。 这只是测试他们在加入查询时是否可以使用索引。

你知道我的意思吗? 这意味着他们可以在加入时使用索引。

那么是否存在任何环境变量问题或密钥长度限制或其他问题?

谢谢你读我。