查询的运行时间极其不成比例。试图理解 RDBMS
Posted
技术标签:
【中文标题】查询的运行时间极其不成比例。试图理解 RDBMS【英文标题】:extremly disproportionate running time for query. Trying to understand RDBMS 【发布时间】:2015-05-29 15:52:53 【问题描述】:我正在使用我们公司只有读取访问权限的客户数据库 (db2)。因此,我无法控制索引、模式等。我想强调这一点,因为可能还有我不知道在哪里的索引。所以我必须以不同的方式优化我们的查询。无论如何,我更感兴趣的是了解这些事情是如何工作的,而不是解决方法(尽管我也对此感兴趣)。我希望 DB 能够快速完成此类操作,但显然并非如此。或者,也许我遇到了一个严重的陷阱。
场景:
我剖析了我们的查询,并将其剥离为以下我无法理解的内容。让我们将此查询称为q1
,其形式为
select c.cid, c.bid, c.ryear, t.tyear, td.nr
from mySchema.cTable c
join mySchema.dTable d on d.cid = c.cid
join mySchema.ipTable ip on (ip.did = d.did and ip.type = 'type_s')
join mySchema.tTable t on t.xtime = ip.xtime
join mySchema.tdTable td on c.tdid = 'type_'||td.oid
where
c.ryear = 2009
and d.rr = 'ugk'
and d.stat = 'stat#1'
;
此查询检索大约 8000 个条目,执行时间超过一分钟。
现在奇怪的部分是:如果我删除 where
子句中的任何一个条件,则执行查询所需的时间不到 2 秒。只是为了完整性:在我删除 ryear 的情况下,结果集返回大约 10000 个条目。如果我删除d.stat = 'stat#1'
,结果集包含大约45000个条目,如果我删除d.rr = 'ugk'
,我实际上得到的结果与我不删除它完全相同(即在这种特定情况下,这个条件对于结果来说是多余的设置)。
如果我同时具备所有 3 个条件,谁能解释我如何/为什么会发生这种巨大的时差?如果我简单地设置 2 个条件,然后在 cli 上 grep 为第三个条件,我会快得多。 DB到底在做什么?
注意:我正在使用 DbVisualizer 来运行我的查询。当我说在时间 x 中执行时,我指的是查询的执行时间,而不是获取时间(参见:http://www.dbvis.com/forum/thread.jspa?threadID=1536)。尽管如果我有所有 3 个语句(大约 10 分钟!)来检索与排除和 d.rr = 'ugk'
部分完全相同的结果,则提取时间也会急剧增加。对于我只有 2 个条件的情况,获取时间最多为 10 秒(即检索 45000 个条目时)。为了完整起见,如果我根本没有where
,我会得到 130000 个条目(执行:1.8 秒,获取 28 秒)
我的问题:发生了什么事? where 子句中的单个语句能否将 dbs 执行计划破坏得如此糟糕?
p.s.:很抱歉,表/列的名称没有更具表现力,但出于显而易见的原因,我不得不对它们进行一些混淆。 p.p.s.:如果你能找到更合适的东西,我很乐意编辑标题。
【问题讨论】:
连接太多 + 有很多数据 + 非最佳条件 = 性能不佳 至少,c.tdid = 'type_' || td.oid
中的连接可能没有任何帮助(可能会使连接中索引的使用无效)。这对这里的行为有多大影响并不完全明显......
一些额外的附注:1) 极端的运行时间可能表明索引统计信息已过时,如有必要,可以运行特定命令来更新这些信息(显然,您不能自己运行它)。 2)您可以查询information schema about indices,您几乎可以肯定需要此信息来智能地计划未来的查询。就此而言,DBVIS 也应该告诉您这些信息(作为 EXPLAIN 计划的一部分)。
【参考方案1】:
慢查询通常表示全表扫描。你一般一切都通过索引而不是表扫描来。 IBM Data Studio 中可能有工具可以帮助您确定表扫描的原因。
我建议以下索引:
SET SCHEMA mySchema;
CREATE INDEX cTable_ryear ON cTable(ryear) INCLUDE (cid, bid, tdid);
CREATE INDEX dTable_rr_stat_cid ON dTable(rr, stat, cid) INCLUDE (did);
CREATE INDEX ipTable_did_type ON ipTable(did, type) INCLUDE (xtime);
CREATE INDEX tTable_xtime ON tTable(xtime) INCLUDE (tyear);
可能还有一种方法可以优化对 tdTable 的访问。
【讨论】:
我说的第一件事是,我只有读取权限。因此我无法创建索引。 @dingalapadum - 在某些时候,您要么必须接受按原样运行事物的成本,要么花费资源(数据库空间)。如果这通常运行,您的 DBA 应该能够为您提供帮助。【参考方案2】:你能告诉我们有哪些索引(SYSIBM.SYSINDEXES
)吗?
也许您可以使用 WITH
又名临时表将查询分成 2...
【讨论】:
以上是关于查询的运行时间极其不成比例。试图理解 RDBMS的主要内容,如果未能解决你的问题,请参考以下文章