Oracle:同一服务器上的数据库之间的性能差异 300 倍

Posted

技术标签:

【中文标题】Oracle:同一服务器上的数据库之间的性能差异 300 倍【英文标题】:Oracle: 300 times difference in performance between databases on same server 【发布时间】:2010-07-02 12:15:37 【问题描述】:

我正在使用 oracle 9.2.0.3.0 服务器上的新旧数据库。

对新数据库中表的查询比对旧数据库中表的相同查询慢大约 300 倍。

这些数据库非常相似,但也有一些区别:

我在旧表中测试的表有一个 CHAR 列(索引)和 12 个 NUMBER 列。 我在新表中测试的表有一个 NUMBER 列(索引)而不是 CHAR 列、13 个 NUMBER 列和 10 个新的 VARCHAR2 列,大小限制为 40-100。 两个表的索引方式相同(除了列的类型...)

两个表都有大约 1900000 条记录。 我的查询在两种情况下都得到了相同的执行计划(使用了索引,没有全扫描) 数据库在不同的表空间中,但在同一个磁盘上。 旧表空间的使用率约为 70%,新表空间的使用率为 94%,否则设置相同(据我所知)。 表空间内的碎片还不错,但旧的更糟(是的!) 由于新表的列更多,因此它使用的块是旧表的三倍。

关于如何进行的任何想法?

更新 1: 在新数据库上运行 10 次查询后,速度下降到大约 80 倍。改进!然而仍然没有解决。

更新 2: 由于列类型更改,查询确实略有不同。首先是旧的(快),然后是新的(慢 80-300 倍)。

SELECT fhin, SUM(cost) 
FROM olddb.oldtable 
WHERE month in ('1004 ') AND fhin IN ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '22', '23', '24', '25', '26', '27', '28', '29', '30', '40', '99') 
GROUP BY fhin

SELECT fhin, SUM(cost) 
FROM newdb.newtable 
WHERE month IN (201004) AND fhin IN ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '22', '23', '24', '25', '26', '27', '28', '29', '30', '40', '99') 
GROUP BY fhin;

请不要问为什么查询看起来像这样,它不是我的;-)

更新 3: 用旧查询解释统计信息:

execution schema (my translation to English)
----------------------------------------------------------
0      SELECT STATEMENT Optimizer=CHOOSE
1    0   SORT (GROUP BY)
2    1     TABLE ACCESS (BY INDEX ROWID) OF 'OLDTABLE'
3    2       INDEX (RANGE SCAN) OF 'OLDTABLE' (NON-UNIQUE)

Statistics
----------------------------------------------------------
      0  recursive calls
      0  db block gets
    182  consistent gets
    101  physical reads
      0  redo size
    903  bytes sent via SQL*Net to client
    398  bytes received via SQL*Net from client
      3  SQL*Net round trips to/from client
      1  sorts (memory)
      0  sorts (disk)
     28  rows processed

解释新查询的统计信息:

execution schema (my translation)
----------------------------------------------------------
0      SELECT STATEMENT Optimizer=CHOOSE (Cost=36 Card=30 Bytes=360)
1    0   SORT (GROUP BY) (Cost=36 Card=30 Bytes=360)
2    1     TABLE ACCESS (BY INDEX ROWID) OF 'NEWTABLE' (Cost=11 Card=13857 Bytes=166284)
3    2       INDEX (RANGE SCAN) OF 'NEWTABLE' (NON-UNIQUE) (Cost=1 Card=22502)

Statistics
----------------------------------------------------------
      0  recursive calls
      0  db block gets
  11019  consistent gets
  11018  physical reads
      0  redo size
    906  bytes sent via SQL*Net to client
    398  bytes received via SQL*Net from client
      3  SQL*Net roundtrips to/from client
      1  sorts (memory)
      0  sorts (disk)
     28  rows processed

我猜他们毕竟不是那么相似。有什么想法吗?

更新 4: 感谢您提供的所有出色帮助!问题仍未解决,但我的客户在接下来的两周内无法联系。届时我会尝试一切并返回这里进行进一步的更新!

更新 5:我又回来了!我运行了 A. Musch 建议的聚类因子分析,发现:

Table   Clustering Factor   Rows    Blocks
Old     12633               1930000 12645
New     938379              1890000 39677

我猜问题是我们在新数据库中有一个错误的集群因素。有关如何解决此问题的任何想法或链接?

更新 6:感谢 Adam 的提示,我找到了这篇关于 Oracle B-tree 索引和集群因子 http://richardfoote.files.wordpress.com/2007/12/index-internals-rebuilding-the-truth.pdf 的文章,并按照说明通过按索引列重新排序表来优化集群因子.问题解决了!

【问题讨论】:

请在两个数据库中发布相关查询的 tkprof。 我不确定我知道该怎么做,但我会试一试! 好吧,如果我没记错的话,tkprof 需要访问服务器的命令提示符。我在一个环境非常封闭的客户那里参加了一次非常短暂的演出。我什至无法访问本地命令提示符。叹息.. @8DH:是的,您需要访问服务器才能检索跟踪文件。我要求提供 tkprof,因为它是确定正在使用的实际执行计划的最佳方法之一。如果您无权访问服务器,请使用 SQL*PLUS SET AUTOTRACE TRACEONLY EXPLAIN STATISTICS 的输出发布一个相关查询(在两个数据库中) @Alex Poole:不,两种情况都不是。月份列上只有一个索引。 【参考方案1】:

您是否注意到坏查询的 I/O 是好查询的 50-100 倍?

Fast Version I/O:
    182  consistent gets 
    101  physical reads 

Slow Version I/O
  11019  consistent gets 
  11018  physical reads 

我很想看看每个系统的驱动索引(每月的一个?)的聚类因子 (ALL_INDEXES.CLUSTERING_FACTOR) 以及它与行数 (COUNT(*)) 和块数的比较(DBA_SEGMENTS.BLOCKS) 来自基础表。

【讨论】:

我会在回到站点时尝试获取该信息。那是在星期一或两周后:\ 很高兴它有帮助。要考虑的一件事是让表按索引组织;那么数据将始终围绕表的主键聚集,驱动索引的聚集因子将始终是块数。这将要求此查询的驱动列(月份?)是主键的一部分。【参考方案2】:

新数据库的统计信息是最新的吗?

【讨论】:

谢谢,为新数据库更新了统计信息。不幸的是没有改善。 它们是否也是旧数据库的最新版本?我遇到过一种情况,我复制了一个数据库,新数据库收集了统计数据,但旧数据库从来没有,这使事情产生了很大的偏差。如果旧的没有统计数据,看看从新的中删除它们是否会产生影响可能会很有趣。 (而不是碰旧的,这可能不受欢迎)。 @Alex Pole:不,它们在旧数据库中已经很老了。我试图删除新的统计信息,但没有改善。【参考方案3】:

1.它是否始终慢 300 倍?或者旧数据库是否已经缓存了所有内容?

2.另外,你说的话让我很奇怪。

数据库是分开的 表空间但在同一个磁盘上。

当然,它们在不同的表空间中——它们必须在。你是想说别的吗?

3.是否在两个数据库都运行时进行比较?换句话说,旧数据库是否具有相同数量的可用资源?您是否将所有内存分配给旧数据库而没有为新数据库留下任何内容?我会关闭旧数据库,为新数据库腾出内存,然后再次尝试比较。

【讨论】:

1.旧数据库大约需要 0.03 秒,而新数据库大约需要 330 到 300 倍的时间。当我更新统计数据时,它慢了 330 倍。运行 10 次后,它实际上只慢了 80 倍! #改进! 2. 好吧,我不太擅长oracle。我想我说了一些显而易见的事情;) 3. 我会试试的!对不起我的 oracle 无知,但我在哪里调整分配的内存设置? 您有 dba 吗?我会检查以确保,但我怀疑 v9 会抢占所有内存。但是有一个参数告诉它最小值,您可以通过查看 init.ora 文件或 spfile 找到该参数。您应该查看如何正确调整 SGA、PGA 等的大小。Oracle 提供的此文档可能会有所帮助:(download.oracle.com/docs/cd/B19306_01/server.102/b28051.pdf) 客户有一名 DBA,但该人目前不在。【参考方案4】:

如果查询相同,列类型更改是否会强制索引数据的隐式 to_char()?这会使事情变慢很多;尽管如果执行计划说它仍在使用索引,那么这似乎不太可能。听起来您正在对一个表进行简单查询,但如果没有,是否存在从索引(数字)列到另一个表中的一个仍然是 char 的连接?我原以为更改列类型至少需要对查询进行一些调整。

【讨论】:

我将在我的问题中发布查询。【参考方案5】:

fhin 是改变类型的列吗?在这种情况下,仍在将值与字符进行比较的 in 列表可以解释问题。

【讨论】:

不,改变的是月份列。 出于好奇,我将 fhin in 语句更改为获取数字列表而不是“n”列表。不幸的是,没有变化,仍然慢了 80-300 倍。

以上是关于Oracle:同一服务器上的数据库之间的性能差异 300 倍的主要内容,如果未能解决你的问题,请参考以下文章

同一张表中的行之间的差异(Oracle SQL)

C# 加载非托管 DLL:IIS 上的控制台应用程序和 webapp 之间的巨大性能差异

自定义服务器控件和用户控件之间是不是存在性能差异?

IF 比较期间 ASCII 字符之间的性能差异

重新安装与设置显示之间的性能和内存差异=“无”

Oracle 平台版本之间的差异