Después de Highload ++ Siberia 2019 - 8 tareas de Oracle

Hola

Del 24 al 25 de junio, se celebró la conferencia Highload ++ Siberia 2019 en Novosibirsk. Nuestros muchachos también estuvieron allí en el informe "Bases de contenedores de Oracle (CDB / PDB) y su uso práctico para el desarrollo de software", publicaremos una versión de texto un poco más tarde. Fue genial, gracias olegbunin por organizar, así como a todos los que vinieron.


En esta publicación, nos gustaría compartir con usted las tareas que estaban en nuestro stand para que pueda probar sus conocimientos en Oracle. Bajo el corte: 8 tareas, opciones de respuesta y explicación.

¿Cuál es el valor máximo de la secuencia que veremos como resultado del siguiente script?


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 5
  • 10
  • 25
  • No, habrá un error.

La respuesta
De acuerdo con la documentación de Oracle (citado en 8.1.6):
Dentro de una sola instrucción SQL, Oracle incrementará la secuencia solo una vez por fila. Si una declaración contiene más de una referencia a NEXTVAL para una secuencia, Oracle incrementa la secuencia una vez y devuelve el mismo valor para todas las ocurrencias de NEXTVAL. Si una declaración contiene referencias a CURRVAL y NEXTVAL, Oracle incrementa la secuencia y devuelve el mismo valor para CURRVAL y NEXTVAL, independientemente de su orden dentro de la declaración.

Por lo tanto, el valor máximo corresponderá al número de filas, es decir, 5 .

¿Cuántas filas habrá en la tabla como resultado del siguiente script?


 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 0
  • 3
  • 4 4
  • 5 5
  • 6 6
  • 9 9

La respuesta
De acuerdo con la documentación de Oracle (citada en 11.2):

Antes de ejecutar cualquier instrucción SQL, Oracle marca un punto de rescate implícito (no disponible para usted). Luego, si la declaración falla, Oracle la revierte automáticamente y devuelve el código de error aplicable a SQLCODE en el SQLCA. Por ejemplo, si una instrucción INSERT provoca un error al intentar insertar un valor duplicado en un índice único, la instrucción se revierte.

Una llamada del cliente también se considera y procesa como una sola declaración. Por lo tanto, la primera llamada a HP se completa con éxito al insertar tres registros; la segunda llamada a HP finaliza con un error y revierte el cuarto registro, que logré insertar; la tercera llamada falla y aparecen tres entradas en la tabla .

¿Cuántas filas habrá en la tabla como resultado del siguiente script?


 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 4
  • 5 5
  • 6 6
  • 7 7

La respuesta
De acuerdo con la documentación de Oracle (citada en 11.2):

Una restricción de verificación le permite especificar una condición que cada fila de la tabla debe cumplir. Para satisfacer la restricción, cada fila de la tabla debe hacer que la condición sea VERDADERA o desconocida (debido a un valor nulo). Cuando Oracle evalúa una condición de restricción de verificación para una fila en particular, cualquier nombre de columna en la condición se refiere a los valores de la columna en esa fila.

Por lo tanto, el valor nulo pasará la prueba y el bloque anónimo se ejecutará con éxito hasta que se intente insertar el valor 3. Después de esto, el bloque de procesamiento de errores arrojará la excepción, no se producirá la reversión y la tabla tendrá cuatro filas con los valores 1, nulo, 2 y nulo nuevamente.

¿Qué pares de valores ocuparán la misma cantidad de espacio en el bloque?


 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 y X
  • B e Y
  • C y K
  • C y Z
  • K y Z
  • Yo y j
  • J y X
  • Todos enumerados

La respuesta
Aquí hay extractos de la documentación (12.1.0.2) para almacenar varios tipos de datos en Oracle.

Tipo de datos Char
El tipo de datos CHAR especifica una cadena de caracteres de longitud fija en el conjunto de caracteres de la base de datos. Usted especifica el juego de caracteres de la base de datos cuando crea su base de datos. Oracle garantiza que todos los valores almacenados en una columna CHAR tengan la longitud especificada por tamaño en la semántica de longitud seleccionada. Si inserta un valor que es más corto que la longitud de la columna, Oracle vacía el valor a la longitud de la columna.

Tipo de datos VARCHAR2
El tipo de datos VARCHAR2 especifica una cadena de caracteres de longitud variable en el juego de caracteres de la base de datos. Usted especifica el juego de caracteres de la base de datos cuando crea su base de datos. Oracle almacena un valor de carácter en una columna VARCHAR2 exactamente como lo especifica, sin ningún espacio en blanco, siempre que el valor no exceda la longitud de la columna.

NÚMERO Tipo de datos
El tipo de datos NUMBER almacena números fijos cero y positivos con valores absolutos desde 1.0 x 10-130 hasta 1.0 x 10126, pero sin incluirlos. Si especifica una expresión aritmética cuyo valor tiene un valor absoluto mayor o igual a 1.0 x 10126, luego Oracle devuelve un error. Cada valor NUMBER requiere de 1 a 22 bytes. Teniendo esto en cuenta, el tamaño de la columna en bytes para un valor de datos numéricos particular NÚMERO (p), donde p es la precisión de un valor dado, se puede calcular utilizando la siguiente fórmula: REDONDEAR ((longitud (p) + s) / 2)) + 1 donde s es igual a cero si el número es positivo, y s es igual a 1 si el número es negativo.

Además, tomamos un extracto de la documentación sobre el almacenamiento de valores nulos.

Un nulo es la ausencia de un valor en una columna. Los valores nulos indican datos faltantes, desconocidos o inaplicables. Los nulos se almacenan en la base de datos si caen entre columnas con valores de datos. En estos casos, requieren 1 byte para almacenar la longitud de la columna (cero). Los nulos finales en una fila no requieren almacenamiento porque un nuevo encabezado de fila indica que las columnas restantes en la fila anterior son nulas. Por ejemplo, si las últimas tres columnas de una tabla son nulas, no se almacenan datos para estas columnas.

En base a estos datos, construimos razonamiento. Creemos que la base de datos utiliza la codificación AL32UTF8. En esta codificación, las letras rusas ocuparán 2 bytes.

1) A y X, el valor del campo a 'Y' es 1 byte, el valor del campo x 'D' es 2 bytes
2) B e Y, 'Vasya' en el valor b se complementará con espacios de hasta 10 caracteres y ocupará 14 bytes, 'Vasya' en d - tomará 8 bytes.
3) C y K. Ambos campos son NULL, después de ellos hay campos significativos, por lo que ocupan 1 byte.
4) C y Z. Ambos campos son NULL, pero el campo Z es el último en la tabla, por lo que no ocupa espacio (0 bytes). El campo C ocupa 1 byte.
5) K y Z. Similar al caso anterior. El valor en el campo K es 1 byte, en Z - 0.
6) I y J. Según la documentación, ambos valores tomarán 2 bytes cada uno. Consideramos la longitud de acuerdo con la fórmula tomada de la documentación: round ((1 + 0) / 2) +1 = 1 + 1 = 2.
7) J y X. El valor en el campo J tomará 2 bytes, el valor en el campo X tomará 2 bytes.

En total, las opciones correctas son: C y K, I y J, J y X.


¿Cuál será aproximadamente el factor de agrupación del índice 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); 

  • Sobre docenas
  • Sobre cientos
  • Del orden de miles
  • Del orden de decenas de miles

La respuesta
De acuerdo con la documentación de Oracle (citada en 12.1):

Para un índice de árbol B, el factor de agrupación de índice mide la agrupación física de filas en relación con un valor de índice.

El factor de agrupación de índice ayuda al optimizador a decidir si una exploración de índice o una exploración de tabla completa es más eficiente para ciertas consultas). Un factor de agrupación bajo indica un escaneo de índice eficiente.

Un factor de agrupación cercano al número de bloques en una tabla indica que las filas están físicamente ordenadas en los bloques de la tabla por la clave de índice. Si la base de datos realiza un escaneo completo de la tabla, la base de datos tiende a recuperar las filas a medida que se almacenan en el disco ordenado por la clave de índice. Un factor de agrupación cercano al número de filas indica que las filas están dispersas aleatoriamente entre los bloques de la base de datos en relación con la clave de índice. Si la base de datos realiza una exploración completa de la tabla, entonces la base de datos no recuperaría filas en ningún orden ordenado por esta clave de índice.

En este caso, los datos se ordenan idealmente, por lo que el factor de agrupación será igual o cercano al número de bloques ocupados en la tabla. Para un tamaño de bloque estándar de 8 kilobytes, puede esperar que alrededor de mil valores de números estrechos quepan en un bloque, por lo que el número de bloques, y como resultado el factor de agrupación, será del orden de las decenas .

¿A qué valores de N se ejecutará con éxito el siguiente script en una base de datos normal con configuración estándar?


 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

La respuesta
De acuerdo con la documentación de Oracle (citada en 11.2):

Límites lógicos de la base de datos.

ArtículoTipo de límiteValor límite
ÍndicesTamaño total de columna indexada75% del tamaño del bloque de la base de datos menos algunos gastos generales

Por lo tanto, el tamaño total de las columnas indexadas no debe exceder los 6Kb. Además depende de la base de codificación seleccionada. Para la codificación AL32UTF8, un carácter puede ocupar un máximo de 4 bytes, por lo que, en el peor de los casos, 6 kilobytes caben aproximadamente 1.500 caracteres. Por lo tanto, Oracle prohibirá la creación de un índice en N = 400 (cuando la longitud de la clave en el peor de los casos es 1600 caracteres * 4 bytes + longitud de fila), mientras que en N = 200 (o menos) la creación del índice funcionará sin problemas.

La instrucción INSERT con la sugerencia APPEND está diseñada para cargar datos en modo directo. ¿Qué sucede si se aplica a la tabla en la que se cuelga el gatillo?


  • Los datos se cargarán en modo directo, el disparador funcionará como debería
  • Los datos se cargarán en modo directo, pero el disparador no se ejecutará.
  • Los datos se cargarán en modo convencional, el disparador funcionará como debería
  • Los datos se cargarán en modo convencional, pero el disparador no se ejecutará
  • Los datos no se cargarán, se solucionará el error

La respuesta
En principio, esto es más una cuestión de lógica. Para encontrar la respuesta correcta, sugeriría el siguiente modelo de razonamiento:

  1. La inserción en modo directo se realiza mediante la formación directa de un bloque de datos, más allá del motor SQL, que garantiza una alta velocidad. Por lo tanto, garantizar la ejecución del disparador es muy difícil, si es posible, y no tiene sentido, ya que de todos modos ralentizará drásticamente la inserción.
  2. Si no se dispara, el hecho de que, con los mismos datos en la tabla, el estado de la base de datos en su conjunto (de otras tablas) dependerá del modo en que se inserten los datos. Obviamente, esto destruirá la integridad de los datos y no se puede aplicar como solución en la producción.
  3. La imposibilidad de realizar la operación solicitada, en general, se trata como un error. Pero aquí debe recordarse que APPEND es una pista, y la lógica general de las pistas es que se tienen en cuenta si es posible, si no, el operador se ejecuta sin tener en cuenta la pista.

Por lo tanto, la respuesta esperada es que los datos se cargarán en modo normal (SQL), el disparador se disparará.

De acuerdo con la documentación de Oracle (citado desde 8.04):

Las violaciones de las restricciones harán que la declaración se ejecute en serie, utilizando la ruta de inserción convencional, sin advertencias ni mensajes de error. Una excepción es la restricción en las declaraciones que acceden a la misma tabla más de una vez en una transacción, lo que puede causar mensajes de error.
Por ejemplo, si los desencadenantes o la integridad referencial están presentes en la tabla, la sugerencia APPEND se ignorará cuando intente utilizar INSERT de carga directa (serie o paralelo), así como la sugerencia o cláusula PARALLEL, si corresponde.

¿Qué sucede al ejecutar el siguiente script?


 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); 

  • Ejecución exitosa
  • Error de sintaxis fallido
  • Error de transacción fuera de línea no válido
  • Error relacionado con exceder el anidamiento máximo de llamadas
  • Error de violación de clave externa
  • Error de bloqueo

La respuesta
La tabla y el desencadenador se crean correctamente y esta operación no debería generar problemas. Las transacciones autónomas en el activador también están permitidas, de lo contrario sería imposible, por ejemplo, el registro.

Después de insertar la primera línea, un activador exitoso conduciría a la inserción de la segunda línea, en relación con la cual el activador funcionaría nuevamente, inserte la tercera línea, y así sucesivamente hasta que la instrucción caiga debido a que excede el máximo de anidamiento de llamadas. Sin embargo, se desencadena otro punto sutil. En el momento en que se ejecuta el desencadenador, la confirmación aún no se ejecuta para el primer registro insertado. Por lo tanto, un desencadenador que funciona en una transacción autónoma intenta insertar una fila en la tabla que hace referencia mediante una clave externa a un registro que aún no se ha confirmado. Esto lleva a una espera (una transacción autónoma está esperando que el compromiso principal comprenda si es posible insertar datos) y, al mismo tiempo, la transacción principal está esperando que el compromiso autónomo continúe funcionando después del desencadenante. Se produce un punto muerto y, como resultado, se devuelve una transacción autónoma por el motivo asociado con los bloqueos .

Source: https://habr.com/ru/post/459680/


All Articles