UUID 作为主键(慢插入)
Posted
技术标签:
【中文标题】UUID 作为主键(慢插入)【英文标题】:UUID as primary key (slow inserts) 【发布时间】:2013-12-10 07:32:14 【问题描述】:我使用 UUID(36 个字符)作为表中的主键。 由于我们达到了大约 150mio 记录,因此插入变得非常慢(似乎是由于 PK 索引)。
有什么办法可以改善这种情况吗?或者你们有什么想法吗?
详情:
1.5 亿行的平均行长。
总共大约 60 个字符(10 列,8 个只是 ID)
慢的定义
每秒 800-1000 行
在加载了多少行之后,它在什么时候变慢了。
afaik 第一个
你是如何加载的(SQL*Loader?SQL?自己的代码?线程?)
Informatica Powercenter
准确的 Oracle 版本(从 v$version 中选择 *)
Oracle 数据库 11g 企业版版本 11.2.0.3.0 - 64 位生产
【问题讨论】:
@MikeW,INSERT DELAYED
是 mysql 独有的功能 - 但这个问题被标记为 Oracle
是什么让你怀疑PK指数?您是否检查过一个会话的跟踪文件,该会话执行了大量插入操作?
您是否使用 Powercenter 调用 Oracle 的直接路径插入,如果您认为您是,您是否检查了日志以确认您是?我记得有大约 3 种不小心不使用它的不同方式。
嗨@user2428207 这些答案是否有助于解决您的问题?如果不是,请在您的问题中添加不成功的内容。当某个答案对您有所帮助时,您是否可以通过单击旁边的空心绿色复选标记来接受它?
【参考方案1】:
首先:每秒 800-1000 行 - 不是那么慢,尤其是来自外部源。我猜你一个接一个地插入行,Oracle 每次都会解析它,然后每次插入之间都有延迟。
关于提高性能:
A.看看你的表上是否有更多索引。
特别是寻找位图索引,因为它们很难重建。
您还可以轻松检查主键是否真的有问题:
alter table <table> drop constraint <primary key>;
B.看看这个表上是否有“物化视图日志”+“提交时物化视图刷新”。这也会很痛。
如果您想获得最快的性能,根本不要在表上使用索引,而是创建第二个在影子中刷新的索引。也许,为此使用物化视图是有道理的。
【讨论】:
数据来自另一个表。当我开始填充该表时,我有大约 10-12k 次插入/秒 尝试删除PK,你会直接看到原因......你总是可以把它变回来 如果数据来自另一个表 - 为什么需要主键?对于“select”语句,PK 几乎是无用的,因为它只包含有关唯一命中的信息,因此比“TABLE ACCESS FULL”慢 我需要 PK 以确保此 UUID 是唯一的。数据来自的表只是从平面文件临时加载数据的暂存区域。 我刚刚检查过了。似乎有一个 PK 约束(唯一)和一个唯一索引。两者都用有意义吗?【参考方案2】:36 个字符的主键不应该成为真正减慢插入行的问题。使用具有唯一值的索引强制执行主键。 36 个字符加上一些开销加上使用 AL32UTF8 时的额外内容,仍然允许 8 KB 块大小在一个索引叶块中容纳许多值。
可能还有其他事情发生。
请定义:
150 M 行的平均行长。 慢的定义 在加载多少行之后,它在什么时候变慢。 如何加载(SQL*Loader?SQL?自己的代码?线程?) 准确的 Oracle 版本(从 v$version 中选择 *)删除索引有帮助
从补充中我了解到,在唯一指标(PK指标)下降后,性能是合理的(22K/s)。
您可能需要检查以下内容:
检查 PowerCenter 正在使用什么后端,这取决于 ETL 作业、版本和平台的可能性。也许是插入/选择,并行是/否,甚至是提取和重新加载。为简单起见,我们假设它是一些并行选择和插入。 11.2.0.3 是一个很好的 Oracle 版本,几乎没有令人讨厌的错误。 根据 DBA 配置空间管理的方式,查看 PK 索引的 initrans 和 maxtrans。第一个确定允许活动的事务数。例如,将 initrans 设置为并发插入的数量。 检查数据字典上的统计信息是否完全不存在或最新(在 dba_tables 中查找实例)。 检查您自己的表上的统计信息是否缺失或相当准确(更改表 xxx 计算所有索引的所有列的表的统计信息)。在加载的数据量和/或分布发生重大变化后重复此步骤。 有时,尤其是在初始加载时,索引可能会变得过于碎片化。也许为 UUID 生成的值对此有所贡献。使用查询可以检测到这一点,但要保持简单:始终在初始加载表后重建索引。随着时间的推移,变化变得越来越小,从 1 行变为 1.000.000 是一个很大的变化,从 100 万变为 200 万则不是。您现在应该只需要这样做一次。附带说明:以 36 个字符的列作为主键的一行 60 个字符似乎不切实际。每个 ID 大约需要精度 / 2 + 1 个字节(BCD 格式)。但即使行大小翻倍,也不会产生重大影响。
检测受益于重建的索引
根据要求添加:
我使用以下查询来确定符合重建条件的索引。最后的标准可以更改。对于 OLTP 环境中的生产使用,它们足以充分减少不必要的消息,但仍能检测到真正的坏情况。以特权用户身份运行或授予对相关数据字典视图的读取权限。应在 Oracle 8、8i、9 和 10 上运行。最近未在 11 或 12 上使用。
我知道直接查询数据字典并不总是可取的,例如在使用数据模型的多个版本时,但这样做的效果要好得多。受益于重建的索引可以通过存储受益(在黑暗时代,我们在 VMS 服务器上只有几 MB,每个 KB 都很有价值),有时还可以提高性能。
ttitle "Warning: Fragmented Indexes (&dbname)" -
skip 2 "Corrective action:" -
skip 1 "Rebuild index (rebuildIndexes.sql)." -
skip 2
column owner format a30 heading "Owner"
column ind_name format a30 heading "Index"
column num_rows format 999,999,990 heading "#Rows"
column cur_size_kb format 9,999,990 heading "Current Size (Kb)"
column est_size_kb format 9,999,990 heading "Est. Size (Kb)"
column ratio format 9,990 heading "Ratio cur/est"
select /*+ rule */ usr.name owner
, objind.name ind_name
, round
(
( sum
( (tab.rowcnt - head.null_cnt) * col.length * 0.5
/* 50% average fill */
)
* 1.5 /* 75% usage after some delet/update */
+ 5 * ts.blocksize
) /1024
) est_size_kb
, round(ts.blocksize * seg.blocks / 1024) cur_size_kb
, round
( ts.blocksize * seg.blocks
/ ( sum((tab.rowcnt - head.null_cnt) * col.length * 0.5) * 1.5
+ 5 * ts.blocksize
)
) ratio
, tab.rowcnt num_rows
from sys.ind$ ind
, sys.hist_head$ head
, sys.col$ col
, sys.icol$ icol
, sys.obj$ objind
, sys.obj$ objtab
, sys.tab$ tab
, sys.ts$ ts
, sys.seg$ seg
, sys.user$ usr
where 1=1
and ts.ts# = seg.ts#
and seg.file# = ind.file#
and seg.block# = ind.block#
and ind.obj# = objind.obj#
and head.col# (+) = col.col#
and head.obj# (+) = col.obj#
and icol.obj# = ind.obj#
and col.col# = icol.col#
and col.obj# = objtab.obj#
/* To save at least 25 Mb, the index must be over 25 Mb. */
and ts.blocksize * seg.blocks > 25 * 1024
and ind.bo# = objtab.obj#
and objind.obj# = ind.obj#
and tab.obj# = objtab.obj#
and objtab.owner# = usr.user#
and usr.name not in ('SYS','SYSTEM')
group
by objind.name
, ts.blocksize
, seg.blocks
, tab.rowcnt
, usr.name
having ts.blocksize * seg.blocks / ( sum((tab.rowcnt - head.null_cnt) * col.length * 0.5) * 1.5 + 5 * ts.blocksize )
>= 2
and ( ts.blocksize * seg.blocks / 1024 )
-
( sum((tab.rowcnt - head.null_cnt) * col.length * 0.5) * 1.5
+ 5 * ts.blocksize
) / 1024
> 25 * 1024
order by 5 desc
【讨论】:
表上还有其他索引吗?对示例运行进行跟踪,看看发生了什么。 在这种情况下,您所说的“碎片化”是什么意思,重建有什么帮助? 重建将所有行点压缩成最小的可能集合。减少 I/O,有时是极端的。还提高了内存的重用性。我记得(在 www 流行之前)来回行驶 1.000 公里只是为了在客户站点重建索引:-)。背景:google,或jonathanlewis.wordpress.com/2010/07/22/fragmentation-4或docs.oracle.com/cd/B19306_01/server.102/b14231/indexes.htm以上是关于UUID 作为主键(慢插入)的主要内容,如果未能解决你的问题,请参考以下文章
mysql创建数据库时怎么将主键设置为UUID,建表语句怎么写
如何将 bigIncrements('id') 转换为 uuid('id') 作为主键?
使用带有 Android 的 Room 使用 UUID 作为主键