【问题标题】:SQL explain plan shows very time-consuming FETCH operationSQL 解释计划显示非常耗时的 FETCH 操作
【发布时间】:2013-03-26 21:57:40
【问题描述】:

我正在处理基于用户选择多个值的登录页面的一些查询,并将它们发送到 DB2 数据库。我正在尝试将它们调整得尽可能快,并取得一些好的结果。但是,有几个查询的执行时间非常难看,比如 10 秒左右。我一直在仔细研究解释计划,发现了一些相当奇怪的东西。

对于初学者来说,这些查询非常简单。有几个内连接、几个左连接和几个过滤条件。他们正在加入一些非常大的表(有些有大约 270 万行)并返回一些非常强大的数据集(最多 30k 行左右,可能有 15 列左右)。问题是,在检查解释计划时,我看到了一个非常奇怪的情况。这是一个 FETCH 操作,占用查询成本的 1/3 到 1/2。此 FETCH 与以下联接有关:

SELECT ...
FROM A
JOIN B
ON B.ID1 = A.ID1
AND B.ID2 = A.ID2
WHERE
B.FIELD IN (:parameter --No more than four strings in here) 

A.ID1 和 2 是 A 的主键,但在 B 中不是唯一的。B.FIELD 总共可能包含十几个不同的字符串值,但该表大约有 270 万行。我看到的是 B 上的一个 FETCH 操作,它包含一个 RIDSCN,它本身包含 B.FIELD IN 子句中每个参数的一个排序操作,每个排序都包含 B 上的索引扫描。令人担忧的是 FETCH 需要多少时间操作正在吃东西,特别是考虑到它是大约十几个连接之一。

我一直在研究索引并且有一些理论,但我不确定问题出在哪里,我自己不能应用任何索引,只能请求它们,所以有点痛苦。 A 在 ID1 和 ID2 上编入索引。 B 也在 ID1 和 ID2 上编入索引。在这些 SORT 操作中,有一个单独的索引用于 B.FIELD(还包含 B 中的一些其他字段)。但是,B 没有专门针对 ID1、ID2、FIEL 的索引。创建此索引是否会减少我在该 FETCH 操作中看到的时间?我不完全确定这是由于缺少适当的索引,或者仅仅是表的大小和列中数据的性质。我已经在几张桌子上请求了 runstats 并查看他们是否会从重组中受益,但如果失败了,我希望有些人能够提供一些启示。我对索引的应用和细微差别还是有点陌生​​。

编辑:这是解释计划的相关部分。可能值得注意的是,这是解释计划树中的第一个操作之一(在一系列 NLJOIN、HSJOIN 等之后):

SCHEMA.B  FETCH                            35.1 %    177046.0625        
    RIDSCN                                   0.0 %     5716.63037109375   
        SORT                                   0.0 %     5257.94189453125   
            B.INDEX  IXSCAN                      1.0 %     5018.35009765625   
        SORT                                   0.0 %     385.5107116699219  
            B.INDEX  IXSCAN                      0.1 %     374.5053405761719  
        SORT                                   0.0 %     50.442073822021484 
            B.INDEX  IXSCAN                      0.0 %     50.34944152832031  
        SORT                                   0.0 %     22.738037109375    
            B.INDEX  IXSCAN                      0.0 %     22.73009490966797  

问题是,我有一些其他查询没有在 IN 子句中显示这种成本,即使返回数千行也是如此。为一个连接使用三分之一的查询成本似乎过高。就像我之前说的,也许它与这个特定的表甚至额外的连接有更多关系,但我真的很想找到一种方法来减少这个数字。

【问题讨论】:

  • “B.FIELD 使用了一个单独的索引(它还包含 B 中的一些其他字段)” B.FIELD 是其中的第一列吗?单独的索引?如果不是,则在评估 B.FIELD IN (...) 时可能不会使用该索引。
  • 它是该索引中的第一个字段,后跟两个 ID 字段,作为 B 的主键,尽管在此查询中没有使用它们。
  • 你能编辑你的问题,然后粘贴 EXPLAIN 的输出吗?我认为排序操作对于 DB2 中的 IN 谓词是正常的。 (对行标识符进行排序可以提高 I/O 的效率。)
  • 这个查询的执行速度有多快:select id1, id2 from B where FIELD in ( <your list > ) ?又返回了多少行?

标签: sql join indexing db2


【解决方案1】:

我不确定这是否应该算作一个答案,但至少还有其他两种等效的方式来表达您的意图。

WHERE B.FIELD = :param1 OR B.FIELD = :param2 ...

SELECT ...
WHERE B.FIELD = :param1
UNION ALL
SELECT ...
WHERE B.FIELD = :param2
...

多年来,我对 DB2 查询优化器有点失去联系。它可能会以不同的方式对待这些逻辑上等价的陈述。这可能不是一件好事。在过去,如果查询优化器为两个逻辑上等价的查询生成了两个不同的执行计划,至少有一个产品认为这是一个错误。 (Rdb?Ingres?不记得了。)

我不太喜欢以这种方式玩弄优化器。今天使用 IN 谓词表现良好的内容可能会因下个月的更新而受损。

就索引的组成而言,我希望开发人员能够将其作为他们工作的常规部分来完成。如果你的雇主不给你一个临时数据库,那么你可以考虑这些替代方案。 (我并不是建议你做任何违反雇主政策的事情。这是被解雇的快速方法。)

  • 大厅 sqlfiddle.com 添加对 DB2 的支持。
  • 设置一台未连接到网络的计算机,并在其上运行DB2 Express-C 进行测试。
  • 在家中设置一台计算机,在其上运行 DB2 Express-C,然后在家中进行测试。
  • 在家中设置一台计算机,设置对其的 SSH 或 VPN 访问,然后从您的工作计算机连接到它。

不要将公司数据转移到公司之外。

如果您无法解决创建索引等问题,请向您的 DBA 提出官方批准的缓慢请求。

【讨论】:

    猜你喜欢
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    相关资源
    最近更新 更多