遵循Highload ++ Siberia 2019-8个Oracle任务

你好

6月24日至25日,Highload ++ Siberia 2019会议在新西伯利亚举行,我们的专家们还参加了报告 “ Oracle容器基础(CDB / PDB)及其在软件开发中的实际使用”,我们将在稍后发布文本版本。 太酷了,谢谢olegbunin的组织,以及所有来的人。


在本文中,我们想与您分享我们展位上的任务,以便您可以测试您在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的第二次调用以错误结束,并回滚了我设法插入的第四条记录; 第三次调用失败, 并且表中出现三个条目

由于以下脚本,表中将有多少行?


 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评估特定行的检查约束条件时,条件中的任何列名称均指该行中的列值。

因此,空值将通过测试,并且匿名块将成功执行,直到尝试插入值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
  • 全部列出

答案
以下摘录自文档(12.1.0.2),用于在Oracle中存储各种数据类型。

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

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

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

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

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

基于这些数据,我们进行推理。 我们认为该数据库使用编码AL32UTF8。 在这种编码中,俄语字母将占据2个字节。

1)A和X,字段“ 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个字节。 我们根据文档中的公式来考虑长度:舍入((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):

逻辑数据库限制

限制类型极限值
指标索引列的总大小数据库块大小的75%减去一些开销

因此,索引列的总大小不应超过6Kb。 进一步取决于所选的编码基础。 对于AL32UTF8编码,一个字符最多可以占用4个字节,因此在最坏的情况下,6 KB可以容纳大约1,500个字符。 因此,Oracle将禁止在N = 400(最坏情况下的密钥长度为1600个字符* 4字节+行标识符长度)下创建索引,而在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); 

  • 成功执行
  • 语法错误失败
  • 无效的离线交易错误
  • 与超出最大呼叫嵌套量有关的错误
  • 外键违反错误
  • 锁定错误

答案
正确创建了表和触发器,此操作不应导致问题。 还允许触发器中的自主事务,否则将是不可能的,例如,日志记录。

插入第一行之后,成功的触发器将导致第二行的插入,与此相关联的触发器将再次起作用,插入第三行,依此类推,直到语句由于超出最大的调用嵌套而下降。 但是,另一个微妙的点被触发。 在执行触发器时,尚未为第一个插入的记录执行提交。 因此,在自主事务中工作的触发器尝试在表中插入由外键引用尚未提交的记录的行。 这导致了等待(自主事务正在等待主提交以了解是否可以插入数据),同时主事务正在等待自主提交在触发器之后继续工作。 发生死锁,结果,由于与锁相关的原因,自治事务将被触发

Source: https://habr.com/ru/post/zh-CN459680/


All Articles