Py学习  »  DATABASE

为什么mysql连接查询-完全扫描不使用索引

jaechoi • 5 年前 • 2014 次点击  

当我只在一个表中选择查询时,我们得到了使用索引的响应,但是当在查询中使用join statemnt时,mysql会对表进行完全扫描吗?

第一查询

select *
    from t_deposit_trx
    where remit_tx_id = '3a33ff14-8d31-45d0-b64f-8a251c4b19a5'

1个简单的T_存款参考T_存款T_汇款ID_指数
使用索引条件的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_结算t_trx range t_结算t_trx_report_date_tx_type_index t_结算t_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'
)

一级T_矿床,全部55724
1个主t_结算t_trx range t_结算t_trx_report_date_tx_type_index t_结算t_trx_report_date_tx_type_index 196 299,使用索引条件;使用where;firstmatch(t_deposit_trx);使用连接缓冲区(flat,bnl join)

我们可以看到上面的结果。 t_settle_trx use range scan and get tx_id and next我希望查询使用索引 “t_settle_trx_report_date_tx_type_索引” 但它使用全扫描…

我不知道为什么?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/40198
 
2014 次点击  
文章 [ 3 ]  |  最新文章 5 年前
jaechoi
Reply   •   1 楼
jaechoi    6 年前

伙计们。。 谢谢你对我的问题感兴趣。

以上两个表在暂存环境和生产环境中具有相同的索引结构。 使用伽辽星团。

我真正想知道的是,他们为什么使用不同的“执行计划”? 特别是在生产环境中,连接查询非常慢。

我昨天做的是…

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'
)

然后先进行“范围扫描”和“索引扫描”。 但两个发送序列值是不同的。它没有任何关系。 这只是测试它们在连接查询时是否可以使用索引。

你知道我的意思吗? 这意味着它们可以在连接时使用索引。

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

谢谢你读我的文章。

tcadidot0
Reply   •   2 楼
tcadidot0    6 年前

我希望这不会比您的第一个查询慢:

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';
Rick James
Reply   •   3 楼
Rick James    6 年前

查询2是 最优的。转动索引:

INDEX(tx_type, report_date)

也就是说,用 = 第一 ,与基数无关。

IN ( SELECT ... ) 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 用一个 加入 从一张桌子开始 WHERE 条款.

(注意:我排列了表和where子句的顺序,这样您就可以看到优化器是如何思考的。表的顺序和where子句的顺序不相关;优化器将根据需要重新排列。)

我的公式应该

  • 充分利用两个表上的索引。
  • 避免全表扫描
  • 第一 它查看的表

全表扫描是 必然是件坏事。如果 一张桌子无论如何都会被触摸,实际上 更快 只需扫描表,而不在索引的btree和数据的btree之间跳转。(你的 具体的 凯斯还有其他不足之处,我把重点放在了这些方面。)

INDEX(tx_type, report_date, tx_id)

是“覆盖”的,因为查询所需的所有列都在一个索引中找到。覆盖“给你一个稍微额外的性能提升。它显示在 EXPLAIN 通过 Using index (不是) Using index condition )

对于tx_seq,这可能是最佳的:

INDEX(tx_type, report_date, tx_seq)