Recuperacion de DB

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 11

CAPÍTULO 11.

SISTEMAS DE GESTIÓN DE BASES DE DATOS 207

REPEATABLE READ: la transacción sólo lee de transacciones finalizadas y lo que lee o escribe
no lo modifican otras transacciones hasta que ella finaliza (sí pueden hacer inserciones, por
lo que puede haber lectura fantasma). Bloquea objetos, pero no conjuntos de objetos. Las
transacciones liberan los bloqueos cuando finalizan.

READ COMMITTED: la transacción sólo lee de transacciones finalizadas y nada escrito por ella
puede ser modificado por otra transacción. Los bloqueos de lectura se liberan inmediatamente.
Los bloqueos de escritura los mantiene hasta que finaliza.

READ UNCOMMITTED: no obtiene ningún tipo de bloqueos. Se requiere que sea READ ONLY (no
puede escribir).

El nivel más aconsejable es el serializable pero hay transacciones que se pueden ejecutar con un
nivel de aislamiento menor. De ese modo se requieren menos bloqueos, lo que puede contribuir a
obtener mejores prestaciones. El nivel de aislamiento y el modo de acceso se puede escoger mediante
la sentencia SET TRANSACTION ISOLATION LEVEL nivel_aislam modo_acceso.
Cuando se definen reglas de integridad en el esquema de la base de datos surge una cuestión:
¿cuándo se comprueba si no se violan estas reglas? Por defecto, una regla de integridad se comprueba
después de cada sentencia SQL que puede hacer que se viole. Si se viola la regla, la sentencia se
rechaza. Sin embargo, este modo de funcionamiento es, a veces, demasiado inflexible. Por ejemplo,
cuando hay un ciclo referencial y ninguna clave ajena del ciclo acepta nulos, no es posible insertar la
primera fila a menos que se pueda retrasar la comprobación de la integridad. Para ello SQL permite
que las restricciones se comprueben de modo inmediato (INMEDIATE) o al final de la transacción
(DEFERRED).

11.7. Recuperación

En todo sistema de bases de datos existe la posibilidad de que ocurra un fallo del sistema o
un fallo en un dispositivo. Si esto sucede y afecta a la base de datos, ésta debe recuperarse. Los
objetivos, tras un fallo, son el asegurar que los efectos de las transacciones finalizadas se reflejen
sobre la base de datos recuperada y volver a encontrarse en un estado operativo tan pronto como
sea posible.
La recuperación de transacciones ante fallos normalmente significa que la base de datos se recarga
con el estado consistente más reciente en el que estuvo justo antes de producirse el fallo. Para hacer
esto, el sistema debe mantener un diario con información sobre los cambios que las transacciones
realizan sobre los datos. La estrategia típica es la siguiente:
208 11.7. RECUPERACIÓN

Si el daño es físico, la base de datos se recupera a partir de la última copia de seguridad y se


rehacen todas las transacciones que habían finalizado cuando se produjo el fallo.

Si el daño no es físico, pero la base de datos está en un estado inconsistente, se deshacen las
operaciones que pueden haber causado la inconsistencia y es posible que haga falta rehacer
otras operaciones.

11.7.1. El diario

Para poder recuperarse, se mantiene un diario (system log) con todas las operaciones que se
van realizando y que afectan a los datos de la base de datos. El diario se mantiene en disco y de
él también se hacen copias de seguridad. Las entradas del diario son, en general, de los siguientes
tipos:

[idT, begin] : empieza la transacción con el identificador idT.

[idT, update, page, length, offset, old, new] : la transacción idT ha actualizado la
página page, la longitud de la actualización es length bytes, la posición el la página en la que
empieza la modificación es offset, el valor anterior de lo modificado es old y el nuevo valor
es new.

[idT, commit] : la transacción idT ha hecho COMMIT.

[idT, abort] : la transacción idT ha abortado.

La recuperación será más o menos complicada de realizar, dependiendo de dos cuestiones fun-
damentales:

¿Qué se hace cuando un bloque de datos que se encuentra en memoria, y que ha sido modificado
por una transacción T, debe ser reemplazado por otro bloque? Si se permiten los robos (steal
approach), el bloque de memoria se escribirá en disco y será reemplazado en memoria. Si no
se permiten robos, este bloque no podrá ser reemplazado hasta que T finalice.

¿Qué se hace cuando una transacción finaliza confirmando sus cambios con COMMIT? Se pueden
guardar forzosamente sus cambios sobre la base de datos (force approach) o bien se pueden
guardar los cambios más adelante, en cualquier otro momento.

Lo más simple para la recuperación es no permitir robos y forzar escrituras. Cuando se permiten
los robos, si algún bloque de una transacción T ha sido robado y T aborta, los cambios realizados
por T sobre los bloques robados se deben deshacer sobre la base de datos. Si no se permiten los
robos, esta situación nunca se dará, por lo que la recuperación será más sencilla. Por otra parte, si
CAPÍTULO 11. SISTEMAS DE GESTIÓN DE BASES DE DATOS 209

no se realiza la escritura forzosa, puede ocurrir que cuando se produzca un fallo del sistema, después
de que una transacción T haya confirmado sus cambios, pero antes de que éstos se hayan reflejado
sobre la base de datos, al volver a poner en marcha el sistema, en la recuperación debe rehacer T.
La recuperación es más sencilla si se fuerza la escritura tras cada confirmación.
Sin embargo, un sistema que no permite robos y que fuerza las escrituras, no es práctico ni
realista. Ya que la memoria es limitada, el hecho de no permitir robos limita la concurrencia. Ya
que las transacciones suelen ser de muy corta duración, el forzar la escritura provoca una cantidad
excesiva de operaciones de entrada/salida. Por lo tanto, lo más apropiado es permitir robos y no
forzar la escritura tras cada confirmación. Lo que se hará es forzar la escritura de los bloques de
memoria cada cierto tiempo. Esta escritura se debe registrar también en el diario y es lo que se
denomina checkpoint.

11.7.2. Algoritmos de recuperación

Hay varios tipos de algoritmos de recuperación:

De actualización diferida (no–undo/redo). La base de datos en disco se actualiza después


de que la transacción haya finalizado. Si una transacción falla, no hay nada que deshacer
(no–undo). Puede que haya que rehacer (redo) algunas operaciones de transacciones que han
finalizado, pero que aún no se han reflejado en disco.

De actualización inmediata (undo/redo). Se hacen actualizaciones en disco antes de que finalice


la transacción. Como también se guardan en el diario, se puede hacer recuperación. Si una
transacción falla, las operaciones se deben deshacer (undo) sobre la base de datos en disco, y
es posible que haya que rehacer (redo) algunas operaciones. Una variación de este algoritmo
hace todas las actualizaciones antes de que la transacción finalice (undo/no–redo).

El SGBD dispone de un área de memoria formada por páginas en las que se almacenan los bloques
de disco que son accedidos. La gestión de este área la realiza el SGBD llamando a rutinas del sistema
operativo. Cada página tiene una variable que indica si el bloque ha sido o no modificado (dirty).
Cuando se reemplaza un bloque, si éste ha sido modificado, hay que volver a escribirlo en disco.
Además, las páginas tienen un contador, denominado pin, que indica el número de transacciones
que han solicitado el bloque y que todavía no lo han liberado. Si no se permiten los robos, sólo se
podrá reemplazar un bloque si su contador tiene el valor cero.

11.7.3. Protocolo de escritura adelantada

Cuando se mantiene un diario para la recuperación, se debe garantizar que los bloques del diario
(que también estarán en memoria) se escriben en disco antes que los bloques de datos a los que
210 11.7. RECUPERACIÓN

afectan las operaciones del diario. Es lo que se denomina write–ahead logging o protocolo de escritura
adelantada.
El subsistema de recuperación del SGBD debe mantener un listado de transacciones activas, así
como un listado de transacciones finalizadas y transacciones abortadas desde el último checkpoint.
Los checkpoint también se registran en el diario. Se registra un checkpoint cuando el sistema escribe
en la base de datos física todas las páginas del SGBD que han sido modificadas (dirty). Todas las
transacciones que hayan finalizado antes del checkpoint, no necesitan ser rehechas en caso de un fallo
del sistema porque todas sus actualizaciones se han realizado sobre la base de datos. Los checkpoint
se realizan habitualmente cada m minutos o cada t transacciones finalizadas. Estos son parámetros
del sistema que fija el administrador de la base de datos.
Hacer un checkpoint consiste en realizar las siguientes operaciones:

Suspender la ejecución de todas las transacciones.

Escribir todas las páginas modificadas en disco.

Escribir el registro de checkpoint en el diario.

Escribir el diario en disco.

Reanudar las ejecuciones de todas las transacciones.

El registro de checkpoint tiene, además, un listado de transacciones activas y su primer y último


registro en el diario (todas las entradas del diario correspondientes a una misma transacción forman
una lista enlazada).
En general, en la recuperación se realizarán las siguientes operaciones:

Deshacer todas las operaciones de actualización de las transacciones activas en el momento


del fallo, que también estaban activas en el último checkpoint.

Rehacer todas las operaciones de escritura de las transacciones finalizadas antes del fallo, que
estaban activas en el último checkpoint.

11.7.4. Recuperación ante fallos en los medios de almacenamiento

Cuando se rompe un disco, para la recuperación se utilizan las copias de seguridad de la base de
datos y las copias de seguridad de los diarios. Las copias de seguridad de los diarios se deben realizar
con más frecuencia que las de la base de datos, porque así se pueden recuperar más transacciones
desde la última copia de seguridad de la base de datos.
CAPÍTULO 11. SISTEMAS DE GESTIÓN DE BASES DE DATOS 211

11.8. Seguridad

El contenido de la base de datos de cualquier organización es un bien corporativo, por lo que se


debe proteger el valor de los datos, garantizar la privacidad y controlar el acceso.
Los objetivos a considerar al diseñar una aplicación de bases de datos segura son:

Privacidad: la información no debe estar disponible para los usuarios no autorizados.

Integridad: sólo los autorizados pueden modificar los datos.

Disponibilidad: los usuarios autorizados no deben ver denegados sus accesos.

Para conseguir estos objetivos se debe establecer una política de seguridad (qué datos proteger y
qué usuarios pueden acceder a qué datos) y utilizar los mecanismos de seguridad del SGBD para
poder seguir esta política.
Los SGBD suelen tener un subsistema de seguridad que se encarga de garantizar la seguridad
de la base de datos frente a accesos no autorizados. Esto es necesario en sistemas de bases de datos
multiusuario en los que no todos los usuarios pueden acceder a cualquier porción de la base de datos.
Hay dos tipos de control de accesos:

Control de accesos discrecional: se basa en privilegios (derechos de acceso). Un privilegio


permite a un usuario acceder a un cierto objeto de una determinada manera (lectura, modi-
ficación, etc.). Cuando un usuario crea un objeto, tiene todos los privilegios sobre él y puede
ceder estos privilegios de forma discrecional a otros usuarios. Este tipo de control es efectivo
pero tiene debilidades: se controla el acceso a los datos, pero después no se controla qué se
hace con ellos.

Control de accesos obligatorio: basado en políticas que abarcan todo el sistema y que no
pueden cambiar los usuarios individuales. Cada objeto de la base de datos tiene un nivel de
seguridad y cada usuario tiene una acreditación para cada nivel de seguridad. Se imponen
unas reglas sobre la lectura y escritura de los objetos por parte de los usuarios. Se trata de
que los datos sensibles no puedan llegar a usuarios sin la acreditación necesaria.

Un segundo problema de seguridad es prevenir que personas no autorizadas accedan al sistema,


bien para obtener información o bien para modificarla. Para restringir el acceso al sistema se realiza
un control de accesos creando cuentas con claves para los usuarios.
Un tercer problema de seguridad es el que aparece en las bases de datos estadísticas. En estas
bases de datos se puede extraer información estadística sobre la población basándose en ciertos
criterios, pero no se puede acceder a la información confidencial sobre individuos concretos. La
212 11.8. SEGURIDAD

protección no es sólo sobre los datos individuales, sino también contra cierto tipo de consultas que
pueden servir para deducir ciertos aspectos individuales.
Un cuarto aspecto sobre seguridad es el cifrado de datos que se utiliza para proteger datos
sensibles, como los números de tarjetas de crédito, y que se envían a través de redes de comunicación.
El administrador de la base de datos es quien se encarga de conceder privilegios a los usuarios,
clasificando datos y usuarios según indique la política de la organización. El administrador de la
base de datos puede realizar las siguientes acciones:

Crear cuentas con claves para usuarios individuales o grupos de usuarios mediante las cuales
puedan acceder al sistema.

Conceder privilegios sobre las cuentas creadas.

Denegar (revocar) privilegios que previamente han sido concedidos.

Asignar niveles de seguridad a las distintas cuentas de usuario.

11.8.1. Control de accesos discrecional

En este apartado consideramos los sistemas de bases de datos relacionales y nos basamos en el
sistema de privilegios que se diseñó para SQL y que forma parte del estándar actual. El SGBD debe
proporcionar acceso selectivo a cada tabla de la base de datos para cada cuenta de usuario concreta.
También se deben controlar las operaciones que se pueden realizar sobre dichas tablas.
Hay dos niveles para asignar privilegios de uso del sistema de base de datos:

A nivel de cuentas de usuario: sobre cada cuenta se establecen unos privilegios independien-
temente de las tablas de la base de datos.

A nivel de las tablas: se pueden controlar los privilegios de acceso sobre cada tabla base o
cada vista de la base de datos.

A nivel de cuentas, los privilegios que se pueden conceder son:

Para crear esquemas o tablas (CREATE SCHEMA, CREATE TABLE).

Para crear vistas (CREATE VIEW).

Para cambiar el esquema añadiendo o eliminando atributos en las tablas (ALTER).

Para insertar, borrar o actualizar tuplas (INSERT, DELETE, UPDATE).

Para realizar consultas (SELECT).


CAPÍTULO 11. SISTEMAS DE GESTIÓN DE BASES DE DATOS 213

A nivel de tablas base y vistas, se especifica para cada usuario qué privilegios tiene sobre cada
una. Algunos privilegios se pueden especificar sobre atributos (columnas) de las tablas/vistas.

GRANT privilegios ON objeto TO usuarios [WITH GRANT OPTION];

Donde un objeto es una tabla base o una vista, y los privilegios pueden ser SELECT, INSERT,
UPDATE, DELETE, REFERENCES(atrib). Con INSERT y UPDATE se puede especificar una lista de atri-
butos que serán aquellos sobre los que se puede insertar y actualizar. El privilegio REFERENCES(atrib)
permite crear tablas base con claves ajenas que referencien al atributo especificado.
Cuando un usuario concede cierto permiso a otro usuario sobre alguno de sus objetos, puede
darle este permiso con la opción GRANT OPTION, lo que permite que el usuario que recibe el permiso
pueda propagar éste a otros usuarios. Se han desarrollado técnicas para limitar la propagación de
privilegios, aunque éstas todavía no han sido implementadas por los SGBD.
En el estándar de SQL los privilegios se otorgan a identificadores de autorización, que algunos
SGBD denominan roles. Una vez creados los roles por parte del administrador de la base de datos,
se puede hacer que cada usuario pertenezca a uno o varios de ellos. De este modo, se facilita la
gestión de los privilegios:

En lugar de otorgar los mismos privilegios explícitamente a distintos usuarios, se otorgan los
privilegios para un grupo de usuarios a un rol y, a continuación, se otorga el rol a esos usuarios.

Si los privilegios de un grupo deben cambiar, sólo es necesario modificar los privilegios del rol
al que pertenecen.

Se puede habilitar y deshabilitar de forma selectiva los roles otorgados a un usuario. Esto
permite controlar los privilegios de un usuario determinado ante una situación dada.

El diccionario de datos almacenará información sobre los roles existentes, por lo que se pueden
diseñar aplicaciones que consulten el diccionario y que automáticamente habiliten (o deshabi-
liten) roles selectivos cuando un usuario trata de ejecutar una aplicación mediante un nombre
de usuario determinado.

Los roles se pueden proteger mediante una palabra clave. Se pueden crear aplicaciones que,
de forma específica, habiliten un rol cuando se da la palabra clave correcta. Los usuarios no
pueden habilitar el rol si no conocen la palabra clave.

Del mismo modo que los SGBD tienen mecanismos para conceder accesos, deben tener meca-
nismos para revocarlos o denegarlos.

REVOKE [ GRANT OPTION FOR ] privilegios ON objeto FROM usuarios


{ RESTRICT | CASCADE };
214 11.8. SEGURIDAD

Con CASCADE, si se quitan los privilegios al usuario X, quedan abandonados los privilegios conce-
didos por X cuando tenía el privilegio con WITH GRANT OPTION. Todos los privilegios que quedan
abandonados son también revocados y así sucesivamente. Con RESTRICT no se revoca el privilegio
si ello provoca que queden privilegios abandonados.
El SGBD mantiene una tabla de privilegios en el diccionario de datos que contiene quién da
cada privilegio, quién lo recibe, el privilegio concedido y si se concede WITH GRANT OPTION. Para
realizar un manejo correcto de las cancelaciones de los privilegios, se pueden dibujar grafos de
autorizaciones, en donde cada nodo es un rol o un usuario y hay un arco por cada privilegio que
se ha concedido. Además hay un nodo denominado sistema del que salen arcos a los nodos que han
creado los objetos (es como si el sistema les hubiera concedido los privilegios que tienen sobre sus
objetos, con la diferencia que no se los pueden revocar). Cuando un usuario A revoca un privilegio
concedido al usuario B, se elimina del grafo el arco que hay de A a B. Esto puede provocar que
queden arcos abandonados, por lo que otros privilegios también serán revocados en consecuencia.
Los únicos arcos que perduran son los que hacen que se cumpla la siguiente afirmación: si un nodo
N tiene arcos de salida, hay un camino del nodo sistema a N con el mismo privilegio y con WITH
GRANT OPTION.
Cuando un usuario recibe privilegios de otros, estos privilegios se tratan como si se hubieran
recibido antes de que él pase ningún otro privilegio a un tercero. Por ejemplo, el usuario A otorga
un privilegio determinado al usuario B, con la opción de propagarlo (WITH GRANT OPTION). A con-
tinuación, el usuario B otorga ese mismo privilegio a C y C, a su vez, se lo otorga a B (siempre
con la opción de propagarlo). Después de esto, el usuario A otorga también el privilegio a C y se
lo revoca a B. Como B ha recibido ese mismo privilegio también de C, y C goza aún del privilegio
otorgado por A, el usuario B no pierde el privilegio, aunque lo recibió de C después de pasárselo a
C él mismo. Sólo si A también lo revoca a C, ambos B y C perderán el privilegio.

11.8.2. Vistas

Mediante las vistas se puede hacer que ciertos usuarios vean solamente ciertos campos o ciertas
filas de una tabla, de modo que las vistas también proporcionan un mecanismo de seguridad adi-
cional: los datos ocultos al usuario mediante la vista no son accesible por él. Por otra parte, cuando
un usuario crea una vista:

Debe tener permiso SELECT sobre todas las tablas sobre las que se define la vista y, por lo
tanto, tendrá permiso SELECT sobre ella.

Podrá pasar el permiso SELECT a otros usuarios si ha recibido dicho permiso con WITH GRANT
OPTION sobre todas las tablas que consulta la vista.
CAPÍTULO 11. SISTEMAS DE GESTIÓN DE BASES DE DATOS 215

Si la vista es actualizable y el usuario tiene privilegios para actualizar las tablas en las que se
basa, entonces también tendrá dichos privilegios sobre la vista.

Cuando un usuario recibe permiso SELECT sobre una vista, puede consultarla pero no puede consultar
directamente las tablas en las que se se basa.
Una vista puede ser eliminada si el creador pierde el privilegio SELECT sobre alguna de las tablas
en las que se basa. Por ejemplo, el usuario A posee la tabla T y concede el privilegio SELECT sobre
T al usuario B. El usuario B crea la vista V1 sobre T y concede el privilegio SELECT al usuario C
sobre V1. A continuación el usuario C crea la vista V2 sobre V1. Si A revoca el privilegio concedido
a B, las vistas V1 y V2 son eliminadas del sistema automáticamente (dejan de existir).
Por otra parte, si se ganan privilegios sobre las tablas, se ganan sobre la vista. Por ejemplo,
siguiendo con el caso anterior, el usuario A concede el privilegio SELECT sobre T al usuario B, éste
crea la vista V1 sobre T y concede el privilegio SELECT al usuario C sobre V1. A continuación el
usuario C crea la vista V2 sobre V1. Si A concede el privilegio INSERT sobre T a B,

si es sin opción de ceder el privilegio, entonces B adquiere el privilegio INSERT sobre V1 pero
no puede cederlo a C;

si es con opción de ceder el privilegio, entonces B adquiere el privilegio INSERT sobre V1 y


puede cederlo a C.

11.8.3. Control de accesos obligatorio

El control de accesos discrecional tiene algunas deficiencias. Una de ellas es que se pueden
introducir caballos de troya. Un caballo de troya es una aplicación que normalmente realiza algo
útil y que además, sin que el usuario lo sepa, se dedica a extraer datos de la base de datos, poniéndolos
a disposición de usuarios no autorizados. Por ejemplo, un usuario A crea una tabla T1. Este usuario
da permiso al usuario B para que pueda realizar inserciones sobre T1. Sin que B lo sepa, A tiene
acceso al código de la aplicación que maneja B e introduce en ella el caballo de troya: desde la
aplicación, que será ejecutada por B, se copian datos de la tabla T2 a la que B tiene acceso, en
la tabla T1 de A, que es un usuario no autorizado a acceder a T2. De este modo, un usuario no
autorizado tiene acceso a los datos porque ha conseguido que un usuario autorizado se los haga
llegar.
El control de accesos discrecional es el que se ha venido utilizando en los sistemas relacionales.
Este es un método de todo o nada: un usuario tiene o no tiene un cierto permiso. En muchas
aplicaciones hace falta una política de seguridad adicional para clasificar datos y usuarios basándose
en clases o niveles de seguridad, de manera que además de controlarse el acceso a los datos, se
controla lo que se hace después con ellos.
216 11.8. SEGURIDAD

La mayoría de los SGBD no proporcionan mecanismos para realizar este tipo de control, aunque
es necesario en cierto tipo de aplicaciones. Las clases o niveles típicos de seguridad son alto secreto
(AS), secreto (S), confidencial (C) y no clasificado (N), donde AS ≥ S ≥ C ≥ N.
El modelo que se suele utilizar para el control de accesos obligatorio es el modelo Bell–LaPadula.
En este modelo se clasifica cada sujeto (usuario, cuenta, programa) y objeto (tabla, fila, columna,
vista, operación) en uno de los niveles de seguridad (AS, S, C, N). Nos referimos a la clasificación
del sujeto S como nivel(S) y a la del objeto O como nivel(O). En el modelo hay dos restricciones
que se deben cumplir en el acceso a los datos:

Propiedad de seguridad simple: el sujeto S puede leer el objeto O sólo si nivel(S)≥nivel(O).

Propiedad *: el sujeto S puede escribir el objeto O sólo si nivel(S)≤nivel(O) (no se puede


escribir un objeto O y darle una clasificación menor que la que el sujeto posee, así se evita
que, por ejemplo, un usuario lea un objeto de AS y lo escriba como N, ya que así dejaría ver
a todos algo que es alto secreto).

Veamos cómo se evitan de este modo los caballos de Troya siguiendo con el ejemplo con el que
hemos empezado este apartado. En este ejemplo, los niveles asignados podrían ser: nivel(B)=S,
nivel(T2)=S y nivel(A)=C. El usuario A sólo puede crear objetos con nivel C o menor, por lo que
nivel(T1)≤C. Cuando la aplicación que maneja B intenta escribir en T1 los datos de T2 el sistema
no permite la operación, ya que nivel(B)>nivel(T1).
Mediante el control de accesos obligatorio se tienen políticas que en muchas ocasiones se consi-
deran demasiado rígidas, por lo que lo normal es combinar ambos controles de acceso.
Bibliografía

[1] C. Batini, S. Ceri, S.B. Navathe (1994)


Diseño Conceptual de Bases de Datos. Un enfoque de entidades–interrelaciones. Addison–
Wesley / Díaz de Santos.

[2] M. Celma, J.C. Casamayor, L. Mota (2003)


Bases de Datos Relacionales. Pearson – Prentice Hall.

[3] T. Connolly, C. Begg, A. Strachan (1998)


Database Systems. A Practical Approach to Design, Implementation and Management. Segunda
edición. Addison–Wesley.

[4] C.J. Date (1995)


An Introduction to Database Systems. Sexta Edición. Addison–Wesley.

[5] R. Elmasri, S.B. Navathe (2002)


Fundamentos de Sistemas de Bases de Datos.
Tercera Edición. Addison–Wesley.

[6] M.J. Hernández (1997)


Database Design for Mere Mortals.
Addison–Wesley Developers Press

[7] R. Ramakrishnan, J. Gehrke (2003)


Database Management Systems. Tercera Edición. McGraw–Hill

217

También podría gustarte