微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

了解rows_examined_per_scan和rows_produced_per_join

如何解决了解rows_examined_per_scan和rows_produced_per_join

我不是MysqL专家,但是最近我有机会使用它-我必须在MysqL5.7上优化一些查询(我也必须在5.6上介绍,但从5.7开始显然有更多信息可以在AWS aurora上运行。这需要很多时间,涉及到一些联接,等等。我从剪切分支开始,选择只对两个表进行“调试”。这些不是太大(〜2M行和〜1.5M行),但是好吧,通常我认为它们的设计不是太好(varchar(255)列上的主键,等等)。

问题是我想研究一下,所以我使用了explain format=json,并且试图从中获得任何见识。

所以,我们说

select cc.id,cc.col1,cc.col2,ct.col1
from my_table cc 
inner join my_table ct on ct.cc_id = cc.id

我得到类似

{
  "query_block": {
    "select_id": 1,"cost_info": {
      "query_cost": "5630369.56"
    },"nested_loop": [
      {
        "table": {
          "table_name": "cc","access_type": "index","possible_keys": [
            "PRIMARY"
          ],"key_length": "258","rows_examined_per_scan": 1248725,"rows_produced_per_join": 1248725,"filtered": "100.00","using_index": true,"cost_info": {
            "read_cost": "3732979.00","eval_cost": "249745.00","prefix_cost": "3982724.00","data_read_per_join": "1G"
          }
        }
      },{
        "table": {
          "table_name": "ct","access_type": "ref","possible_keys": [
            "cc_id_idx"
          ],"key": "cc_id_idx","key_length": "257","ref": [
            "cc.id"
          ],"rows_examined_per_scan": 1,"rows_produced_per_join": 1373037,"cost_info": {
            "read_cost": "1373037.97","eval_cost": "274607.59","prefix_cost": "5630369.56","data_read_per_join": "3G"
          },"used_columns": [
            "id","col_1","col_2",...
          ]
        }
      }
    ]
  }
}

我在理解这里到底发生了什么时遇到了问题。我认为MysqL使嵌套连接从表cc开始,然后对于每一行它都命中ctaccess_typeref"rows_examined_per_scan": 1)。使其> 1M次("rows_produced_per_join": 1373037)。那是对的吗?我一直在寻找有关它的任何文档,但是我没有找到有关如何在加入上下文中读取这些值的任何指定信息-也许仅仅是我的google-fu不够强大。可以给我任何线索吗?

(当我在寻找加速它的任何选项时,我想强制MysqL进行哈希联接,该联接可以在/*+ HASH_JOIN(cc) */形式的aurora(我正在尝试aurora 2.09)上使用,但这绝对不会影响查询计划-而是另一个问题。)

解决方法

select cc.id,cc.col1,cc.col2,ct.col1
    from my_table cc 
    inner join my_table ct  on ct.cc_id = cc.id

如果存在WHERE子句,则可能 导致优化器选择WHERE中提到的表作为{{1}中的“第一”表}。

在没有JOIN的情况下,优化程序通常 选择较小的表。作为“第一”。

然后通常 进行NLJ(嵌套循环连接):

  1. 读取“第一”表的所有行(可能由WHERE过滤)。
  2. 对于每个行,它会到达另一个表(NLJ)。

第2步有时是 通过将整个“第二”表读入内存并构建哈希来完成的。但这仅适用于“较小”的第二张桌子。您的桌子似乎太大了。

之所以提出这些建议,是因为您提出的查询得到了简化; “真实”查询的执行方式可能与WHERE相同。

一些观察结果:

  • “ key_length”是“ big”且不一致-检查声明,包括排序规则。在合理的长度可行的情况下,请勿盲目使用EXPLAIN。在VARCHAR(255)中混合排序规则对性能至关重要。 (没有真正的证据表明查询存在此问题。)
  • 尽管我只是批评JOIN代表VARCHAR(255),但我不同意那些声称它很糟糕并且您“必须”切换到PRIMARY KEY的人的看法。您能告诉我们其中有什么类型的数据吗? UUID vs短字符串vs URL vs ...-根据数据的不同,可能适用不同的优化技术。
  • “ using_index”:true-这意味着在使用的INT中可以找到该查询表中所需的所有列。这对性能有好处。但是,如果在INDEX子句中添加另一列,则可以消除这种情况。
  • “ used_columns”-列表似乎比查询所需的时间更长?索引中是否有很多列? SELECT与查询不匹配吗?
  • “哈希”很少比“ BTree”更好。 (我不了解Aurora的具体信息,因此我无法说出您尝试过的索引提示。)

如所写的那样,简单的查询将花费很长时间-扫描一个表(或索引),并对另一个表进行大量BTree查找。

回到您的原始问题。这是我在说明中看到的:

  • “嵌套循环” == NLJ,如预期并如上所述。
  • 大笔费用-加入大桌子时将要发生的事
  • “使用索引” ==很好,但是唯一的“可能的键”是“ PRIMARY”。因此,它实际上是表扫描,而不是“索引扫描”。
  • “键长”-见上文
  • “ Used_columns”-参见上文
  • access_type是ref和“ rows_examined_per_scan”:1-查找(请参见上文)。但是请注意,“ rows_scanned”是一个估计值。实际值取决于EXPLAIN是否为cc_id
  • “ rows_produced_per_join”-没那么重要

对于此类问题,请提供UNIQUE

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?