追随 Highload++ Siberia 2019 的脚步 - Oracle 上的 8 项任务

您好!

24月25-2019日,Highload++ Siberia XNUMX会议在新西伯利亚举行,我们的人员也参加了 报告 “Oracle容器数据库(CDB/PDB)及其在软件开发中的实际用途”,我们稍后将发布文本版本。 太酷了,谢谢 油酸蛋白 为了这个组织,也为了每一个来的人。

追随 Highload++ Siberia 2019 的脚步 - Oracle 上的 8 项任务
在这篇文章中,我们想与您分享我们在展位上遇到的问题,以便您测试您的 Oracle 知识。 剪辑下方有 8 个问题、答案选项和解释。

执行以下脚本后我们将看到的最大序列值是多少?

create sequence s start with 1;
 
select s.currval, s.nextval, s.currval, s.nextval, s.currval
from dual
connect by level <= 5;

  • 1
  • 5
  • 10
  • 25
  • 不,会有错误

回答根据Oracle文档(引自8.1.6):
在单个 SQL 语句中,Oracle 每行只会递增序列一次。 如果一条语句包含多个对某个序列的 NEXTVAL 的引用,则 Oracle 会将该序列递增一次,并为所有出现的 NEXTVAL 返回相同的值。 如果语句包含对 CURRVAL 和 NEXTVAL 的引用,则 Oracle 会递增序列并为 CURRVAL 和 NEXTVAL 返回相同的值,无论它们在语句中的顺序如何。

因此, 最大值将对应行数,即 5.

运行以下脚本后,表中将有多少行?

create table t(i integer check (i < 5));
 
create procedure p(p_from integer, p_to integer) as
begin
    for i in p_from .. p_to loop
        insert into t values (i);
    end loop;
end;
/
 
exec p(1, 3);
exec p(4, 6);
exec p(7, 9);

  • 0
  • 3
  • 4
  • 5
  • 6
  • 9

回答根据Oracle文档(引自11.2):

在执行任何 SQL 语句之前,Oracle 会标记一个隐式保存点(您不可用)。 然后,如果该语句失败,Oracle 将自动回滚该语句,并将适用的错误代码返回到 SQLCA 中的 SQLCODE。 例如,如果 INSERT 语句尝试在唯一索引中插入重复值而导致错误,则该语句将回滚。

从客户端调用 HP 也被视为单个语句并进行处理。 因此,第一个 HP 调用成功完成,插入了三个记录; 第二个 HP 调用以错误结束,并回滚它设法插入的第四条记录; 第三次调用失败, 并且表中有XNUMX条记录.

运行以下脚本后,表中将有多少行?

create table t(i integer, constraint i_ch check (i < 3));
 
begin
    insert into t values (1);
    insert into t values (null);
    insert into t values (2);
    insert into t values (null);
    insert into t values (3);
    insert into t values (null);
    insert into t values (4);
    insert into t values (null);
    insert into t values (5);
exception
    when others then
        dbms_output.put_line('Oops!');
end;
/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

回答根据Oracle文档(引自11.2):

检查约束允许您指定表中每一行必须满足的条件。 为了满足约束,表中的每一行必须使条件为 TRUE 或未知(由于为空)。 当Oracle评估特定行的检查约束条件时,条件中的任何列名都引用该行中的列值。

因此,值 null 将通过检查,匿名块将成功执行,直到尝试插入值 3。此后,错误处理块将清除异常,不会发生回滚,并且 表中将剩下四行 值为 1、null、2 和 null。

哪对值会在块中占用相同的空间?

create table t (
    a char(1 char),
    b char(10 char),
    c char(100 char),
    i number(4),
    j number(14),
    k number(24),
    x varchar2(1 char),
    y varchar2(10 char),
    z varchar2(100 char));
 
insert into t (a, b, i, j, x, y)
    values ('Y', 'Вася', 10, 10, 'Д', 'Вася');

  • A和X
  • B和Y
  • C和K
  • C和Z
  • K 和 Z
  • 我和J
  • J和X
  • 全部列出

回答以下是有关在 Oracle 中存储各种类型数据的文档 (12.1.0.2) 的摘录。

CHAR 数据类型
CHAR 数据类型指定数据库字符集中的固定长度字符串。 您在创建数据库时指定数据库字符集。 Oracle 确保存储在 CHAR 列中的所有值都具有选定长度语义中 size 指定的长度。 如果插入的值短于列长度,则 Oracle 会将该值空白填充到列长度。

VARCHAR2 数据类型
VARCHAR2 数据类型指定数据库字符集中的可变长度字符串。 您在创建数据库时指定数据库字符集。 Oracle 完全按照您指定的方式将字符值存储在 VARCHAR2 列中,没有任何空白填充,前提是该值不超过列的长度。

数字数据类型
NUMBER 数据类型存储零以及绝对值从 1.0 x 10-130 到但不包括 1.0 x 10126 的正负固定数。如果指定一个算术表达式,其值的绝对值大于或等于1.0 x 10126,则 Oracle 返回错误。 每个 NUMBER 值需要 1 到 22 个字节。 考虑到这一点,可以使用以下公式计算特定数值数据值 NUMBER(p) 的列大小(以字节为单位),其中 p 是给定值的精度: 圆形((长度(p)+s)/2))+1 其中,如果数字为正,则 s 等于 1;如果数字为负,则 s 等于 XNUMX。

另外,我们摘录一下有关存储 Null 值的文档。

null 是指列中不存在值。 空值表示缺失、未知或不适用的数据。 如果空值位于具有数据值的列之间,则空值将存储在数据库中。 在这些情况下,它们需要 1 个字节来存储列的长度(零)。 行中的尾随空值不需要存储,因为新的行标题表明前一行中的其余列为空。 例如,如果表的最后三列为空,则不会为这些列存储任何数据。

基于这些数据,我们建立推理。 我们假设数据库使用AL32UTF8编码。 在这种编码中,俄语字母将占用2个字节。

1)A和X,a字段'Y'的值占1字节,x字段'D'的值占2字节
2) B 和 Y,b 中的“Vasya”值将用空格填充,最多 10 个字符,将占用 14 个字节,d 中的“Vasya”将占用 8 个字节。
3)C和K。这两个字段的值为NULL,后面有重要字段,因此占用1个字节。
4)C和Z。两个字段的值都是NULL,但字段Z是表中的最后一个,因此它不占用空间(0字节)。 字段C占用1字节。
5)K和Z。与之前的情况类似。 K字段中的值占用1个字节,在Z-0中。
6)I和J。根据文档,这两个值都将占用2个字节。 我们使用文档中的公式计算长度:round( (1 + 0)/2) +1 = 1 + 1 = 2。
7) J和X。J字段中的值将占用2个字节,X字段中的值将占用2个字节。

总共,正确选项是:C 和 K、I 和 J、J 和 X。

T_I 索引的聚类因子大约是多少?

create table t (i integer);
 
insert into t select rownum from dual connect by level <= 10000;
 
create index t_i on t(i);

  • 约数十
  • 约数百
  • 约数千
  • 约数万

回答根据Oracle文档(引自12.1):

对于 B 树索引,索引聚集因子衡量与索引值相关的行的物理分组。

索引集群因子帮助优化器决定对于某些查询来说索引扫描还是全表扫描更有效。 低聚类因子表明索引扫描有效。

接近表中块数的聚簇因子表示表块中的行按索引键物理排序。 如果数据库执行全表扫描,则数据库倾向于检索存储在磁盘上并按索引键排序的行。 接近行数的聚类因子表示行相对于索引键随机分散在数据库块中。 如果数据库执行全表扫描,则数据库将不会按此索引键以任何排序顺序检索行。

在这种情况下,数据是理想排序的,因此聚类因子将等于或接近表中占用的块的数量。 对于 8 KB 的标准块大小,您可以预期大约一千个窄数值将适合一个块,因此块的数量以及结果的聚类因子将是 大约几十.

在标准设置的常规数据库中,N 的值是多少时,以下脚本将成功执行?

create table t (
    a varchar2(N char),
    b varchar2(N char),
    c varchar2(N char),
    d varchar2(N char));
 
create index t_i on t (a, b, c, d);

  • 100
  • 200
  • 400
  • 800
  • 1600
  • 3200
  • 6400

回答根据Oracle文档(引自11.2):

逻辑数据库限制

Item
限额类型
极限值

指数
索引列的总大小
数据库块大小的 75% 减去一些开销

因此,索引列的总大小不应超过 6Kb。 接下来发生的情况取决于所选的基本编码。 对于 AL32UTF8 编码,一个字符最多可以占用 4 个字节,因此在最坏的情况下,6 KB 可以容纳大约 1500 个字符。 因此,Oracle将不允许在N = 400时创建索引(当最坏情况键长度为1600个字符* 4字节+ rowid长度时),而 N = 200(或更少) 创建索引将毫无问题地工作。

带有 APPEND 提示的 INSERT 运算符旨在以直接模式加载数据。 如果将其应用于触发器挂起的表会发生什么?

  • 数据将以直接模式加载,触发器将按预期工作
  • 直接模式会加载数据,但不会执行触发器
  • 数据将以常规模式加载,触发器将按其应有的方式工作
  • 会以常规方式加载数据,但不会执行触发器
  • 数据不会被加载,会记录错误

回答基本上,这更多的是一个逻辑问题。 为了找到正确的答案,我建议采用以下推理模型:

  1. 直接插入方式是直接形成数据块,绕过SQL引擎,速度快。 因此,确保触发器的执行即使不是不可能也是非常困难的,并且这样做没有任何意义,因为它仍然会从根本上减慢插入速度。
  2. 未能执行触发器将导致这样的事实:如果表中的数据相同,则整个数据库(其他表)的状态将取决于该数据插入的模式。 这显然会破坏数据完整性,并且不能作为生产中的解决方案应用。
  3. 无法执行请求的操作通常被视为错误。 但这里我们应该记住,APPEND是一个提示,提示的一般逻辑是,如果可能的话就考虑它们,但如果不能,则在不考虑提示的情况下执行运算符。

所以预期的答案是 数据将以正常(SQL)模式加载,触发器将触发。

根据Oracle文档(引自8.04):

违反限制将导致语句使用常规插入路径串行执行,而不会出现警告或错误消息。 一个例外是限制语句在事务中多次访问同一个表,这可能会导致错误消息。
例如,如果表上存在触发器或引用完整性,则当您尝试使用直接加载 INSERT(串行或并行)以及 PARALLEL 提示或子句(如果有)时,将忽略 APPEND 提示。

执行下面的脚本会发生什么?

create table t(i integer not null primary key, j integer references t);
 
create trigger t_a_i after insert on t for each row
declare
    pragma autonomous_transaction;
begin
    insert into t values (:new.i + 1, :new.i);
    commit;
end;
/
 
insert into t values (1, null);

  • 执行成功
  • 由于语法错误而失败
  • 错误:自主交易无效
  • 与超出最大调用嵌套相关的错误
  • 外键违规错误
  • 与锁相关的错误

回答表和触发器的创建非常正确,此操作不会导致问题。 例如,还允许触发器中的自主事务,否则将无法进行日志记录。

插入第一行后,成功触发触发器将导致插入第二行,从而导致触发器再次触发,插入第三行,依此类推,直到语句由于超出调用的最大嵌套数而失败。 然而,另一个微妙的点也发挥了作用。 执行触发器时,第一条插入记录的提交尚未完成。 因此,在自治事务中运行的触发器尝试在表中插入引用尚未提交的记录的外键的行。 这就导致了等待(自治事务等待主事务提交看是否可以插入数据),同时主事务在触发后等待自治事务继续工作。 发生死锁,导致自治事务因锁相关原因被取消.

只有注册用户才能参与调查。 登录拜托

很难吗?

  • 就像两根手指一样,我立刻就决定了一切。

  • 不完全是,我在几个问题上都错了。

  • 我正确地解决了一半。

  • 我猜了两次答案!

  • 我会写在评论里

14 位用户投票。 10 名用户弃权。

来源: habr.com

添加评论