OEL 6.5 上的 Oracle 11.2.0.4
我们的应用管理员从应用供应商处运行了一些更新脚本,该脚本已经运行了几个小时,没有人知道它什么时候结束。数据库现在还生成大量归档日志。我启动sql trace 15分钟,发现几乎只有一个查询。
INSERT INTO house_t
VALUES
(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15, :16,
:17, :18, :19, :20, :21, :22, :23)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 70 0.00 0.00 0 0 0 0
Execute 71 23.86 633.03 83564 41375 4597750 355735
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 141 23.87 633.03 83564 41375 4597750 355735
为什么一个简单的插入需要在当前模式下使用这么多块 64757=4597750/71 ???
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 103
Number of plan statistics captured: 3
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 LOAD TABLE CONVENTIONAL (cr=584 pr=1443 pw=0 time=11388214 us)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net more data from client 9523 0.00 0.08
db file sequential read 82252 0.60 603.94
SQL*Net message to client 70 0.00 0.00
SQL*Net message from client 70 0.00 0.15
log file switch completion 4 0.08 0.18
undo segment extension 4 0.00 0.01
log file sync 1 0.00 0.00
表结构简单:
SQL> desc house_t
Name Null? Type
-------------------- -------- --------------
POSTALCODE VARCHAR2(6)
IFNSFL VARCHAR2(4)
TERRIFNSFL VARCHAR2(4)
IFNSUL VARCHAR2(4)
TERRIFNSUL VARCHAR2(4)
OKATO VARCHAR2(11)
OKTMO VARCHAR2(11)
UPDATEDATE DATE
HOUSENUM VARCHAR2(20)
ESTSTATUS NUMBER(5)
BUILDNUM VARCHAR2(10)
STRUCNUM VARCHAR2(10)
STRSTATUS NUMBER(5)
HOUSEID VARCHAR2(36)
HOUSEGUID VARCHAR2(36)
AOGUID VARCHAR2(36)
STARTDATE DATE
ENDDATE DATE
STATSTATUS NUMBER(5)
NORMDOC VARCHAR2(36)
COUNTER NUMBER(10)
CADNUM VARCHAR2(100)
DIVTYPE NUMBER(5)
此表上没有触发器,没有 mview,没有定义的 fga 策略,没有 fgac 策略。
表也有3个索引
CREATE UNIQUE INDEX HOUSE_T_IDX0 ON HOUSE_T(HOUSEID);
CREATE INDEX HOUSE_T_IDX1 ON HOUSE_T (T_HOUSEGUID);
CREATE INDEX HOUSE_T_IDX2 ON HOUSE_T (T_AOGUID);
原始跟踪文件在这 3 个索引和撤消块上充满了“db 文件顺序读取”等待。
表现在大约有 50M 记录,大小约为 12Gb。索引大约为 3-4GB,并且在 dba_indexes 中有 blevel=3。
我希望这个插入语句可以运行 20-30 个块,但为什么要运行数千个?
重现步骤:
样本数据:
现在模拟你的脚本:
和 tkprof 输出:
并且数量巨大
leaf node splits
:1) 我在这里使用 SSD,这就是为什么我的演示花费的时间要少得多,因为磁盘响应时间要短得多。您应该查看
current
块的数量,而不是花费在此上的时间。2)我以随机顺序插入数据,这导致
leaf block splits
.leaf node 90-10 splits
是由按顺序递增的顺序将数据插入到索引的最右边部分引起的。leaf node 90-10 splits
可以简单地通过将新的索引块添加到索引的“最右边”部分来完成,然后将最高值复制到其中。有时它被非正式地称为99-1
拆分而不是90-10
.leaf block splits
意味着在索引的“中间”添加新块,在几个块中复制和重新排列数据,这是更多的工作。3) 性能方面,我发现使用 GUID 作为标识符是一个非常糟糕的主意。
NUMBER
与简单标识符相比,它们消耗的存储空间要多出数倍。这是相同的,但有 NUMBER 个类型:
另外:Oracle Cost Based Optimizer 的限制(文档 ID 212809.1)
这导致 GUID 列上的直方图出现一些严重不正确的基数估计错误。
这是当值以递增顺序插入时的行为方式(已删除
order by dbms_random.value
):如您所见,每行少于 1 个当前块。