Este documento forma parte de una serie que proporciona información y directrices clave relacionadas con la planificación y la realización de migraciones de bases de datos Oracle® 11g/12c a la versión 12 de Cloud SQL para PostgreSQL. En este documento se explican las diferencias básicas entre Oracle® Database y Cloud SQL para PostgreSQL en lo que respecta a la creación de usuarios, esquemas, tablas, índices y vistas.
Además de la parte de configuración inicial, la serie incluye las siguientes partes:
- Migrar usuarios de Oracle a Cloud SQL para PostgreSQL: terminología y funciones
- Migrar usuarios de Oracle a Cloud SQL para PostgreSQL: tipos de datos, usuarios y tablas
- Migrar usuarios de Oracle a Cloud SQL para PostgreSQL: consultas, procedimientos almacenados, funciones y activadores
- Migrar usuarios de Oracle a Cloud SQL para PostgreSQL: seguridad, operaciones, monitorización y registro
- Migrar usuarios y esquemas de Oracle Database a Cloud SQL para PostgreSQL (este documento)
Diferencias de terminología entre Oracle y Cloud SQL para PostgreSQL
Oracle y Cloud SQL para PostgreSQL tienen arquitecturas y terminología diferentes para las instancias, las bases de datos, los usuarios y los esquemas. Para ver un resumen de estas diferencias, consulta la parte de terminología de esta serie.
Exportar configuraciones de Oracle
Uno de los primeros pasos a la hora de planificar una migración a Cloud SQL para PostgreSQL es revisar los ajustes de los parámetros de la base de datos de Oracle de origen. Los ajustes relacionados con la asignación de memoria, el conjunto de caracteres y los parámetros de almacenamiento son especialmente útiles porque pueden influir en la configuración inicial y el tamaño del entorno de destino de Cloud SQL para PostgreSQL. Hay varios métodos para extraer la configuración de los parámetros de Oracle. Estos son algunos de los más habituales:
- Los informes de Automatic Workload Repository (AWR) contienen datos de asignación de recursos (CPU, RAM), configuración de parámetros de instancia y sesiones activas máximas.
DBA_HIST
,V$OSSTAT
yV$LICENSE
para ver los detalles del uso de la CPU.V$PARAMETER
para ver los parámetros de configuración de la base de datos.V$NLS_PARAMETERS
para ver los parámetros de idioma de la base de datos.DBA_DATA_FILES
para calcular el tamaño de almacenamiento de la base de datos.- Oracle
SPFILE
para las configuraciones de instancias de bases de datos. - Herramientas de programación de trabajos (por ejemplo,
crontab
) para identificar copias de seguridad rutinarias o ventanas de mantenimiento que se deban tener en cuenta.
Importar y configurar usuarios en Cloud SQL para PostgreSQL
A grandes rasgos, cada esquema de Oracle debe crearse como un esquema independiente en PostgreSQL. En una base de datos de Oracle, user es sinónimo de schema. Esto significa que se crea un esquema al crear un usuario. Siempre hay una relación de 1:1 entre los usuarios y los esquemas. En PostgreSQL, los usuarios y los esquemas se crean por separado. Se puede crear un usuario sin crear un esquema correspondiente. Para mantener la misma estructura de usuario o esquema de Oracle en PostgreSQL, puedes crear un esquema para cada usuario.
En la siguiente tabla se muestran ejemplos de conversiones:
Tipo de acción | Tipo de base de datos | Comparación de comandos |
---|---|---|
Crear usuario y esquema | Oracle |
CREATE USER username IDENTIFIED BY password; |
PostgreSQL |
Los usuarios y los esquemas son conceptos distintos en PostgreSQL, por lo que requieren dos CREATE instruccionesCREATE USER username WITH PASSWORD 'password'; independientes. |
|
Asignar funciones | Oracle |
GRANT CONNECT TO username; |
PostgreSQL |
GRANT pg_monitor TO username; |
|
Concesión de privilegios | Oracle |
GRANT SELECT, INSERT, UPDATE ON HR.EMPLOYEES TO username; |
PostgreSQL |
GRANT SELECT, INSERT, UPDATE ON HR.EMPLOYEES TO username; |
|
Revocar privilegios | Oracle |
REVOKE UPDATE ON HR.EMPLOYEES FROM username; |
PostgreSQL |
REVOKE UPDATE ON HR.EMPLOYEES FROM username; |
|
Conceder DBA o superusuario | Oracle |
GRANT DBA TO username; |
PostgreSQL |
GRANT cloudsqlsuperuser TO username; |
|
Eliminar usuario | Oracle |
DROP USER username CASCADE; |
PostgreSQL |
Los usuarios y los esquemas son conceptos distintos en PostgreSQL, por lo que requieren dos DROP instruccionesDROP USER username; independientes. |
|
Metadatos de usuarios | Oracle |
DBA_USERS |
PostgreSQL |
pg_catalog.pg_user |
|
Metadatos de permisos | Oracle |
DBA_SYS_PRIVS |
PostgreSQL |
pg_catalog.pg_roles |
|
Cadena de conexión de la CLI | Oracle |
sqlplus username/password@host/tns_alias |
PostgreSQL |
Sin petición de contraseña:PGPASSWORD=password psql -h hostname -U username -d database_name Con petición de contraseña: psql -h hostname -U username -W -d database_name |
Usuarios de bases de datos Oracle 12c:
En Oracle 12c hay dos tipos de usuarios: usuarios comunes y usuarios locales. Los usuarios comunes se crean en el CDB raíz, incluidas las PDBs. Se identifican por el prefijo C##
en su nombre de usuario. Los usuarios locales solo se crean en una PDB específica.
Se pueden crear diferentes usuarios de la base de datos con nombres de usuario idénticos en varias PDBs. Cuando migres de Oracle 12c a PostgreSQL, modifica los usuarios y los permisos para adaptarlos a la arquitectura de PostgreSQL. A continuación, te mostramos dos ejemplos habituales para ilustrar estas diferencias:
# Oracle local user SQL> ALTER SESSION SET CONTAINER=pdb; SQL> CREATE USER username IDENTIFIED BY password QUOTA 50M ON USERS; # PostgreSQL user for a single database and schema postgres=> CREATE USER username WITH PASSWORD 'password'; postgres=> GRANT CONNECT TO DATABASE database_name TO username; postgres=> GRANT USAGE ON SCHEMA schema_name TO username; postgres=> -- Optionally, grant object privileges in the schema postgres=> GRANT ALL ON ALL TABLES IN SCHEMA schema_name TO username; postgres=> GRANT ALL ON ALL SEQUENCES IN SCHEMA schema_name TO username; postgres=> GRANT ALL ON ALL FUNCTIONS IN SCHEMA schema_name TO username; postgres=> GRANT ALL ON ALL PROCEDURES IN SCHEMA schema_name TO username; postgres=> GRANT ALL ON ALL ROUTINES IN SCHEMA schema_name TO username; # Oracle common user SQL> CREATE USER c##username IDENTIFIED BY password CONTAINER=ALL; # PostgreSQL user with permissions for all database (use the local user script above and repeat it for each database and schema)
Gestionar usuarios a través de la consola Google Cloud
Para ver los usuarios configurados actualmente en Cloud SQL para PostgreSQL, ve a la página siguiente de la Google Cloud consola:
Google Cloud > Storage > SQL > Instance > Users
Importar definiciones de tablas y vistas
Oracle y PostgreSQL se diferencian en cuanto a la distinción entre mayúsculas y minúsculas. En los nombres de Oracle no se distingue entre mayúsculas y minúsculas. En PostgreSQL no se distingue entre mayúsculas y minúsculas, excepto cuando los nombres están entre comillas dobles. Muchas herramientas de exportación de esquemas y generación de SQL para Oracle, como DBMS_METADATA.GET_DDL
, añaden automáticamente comillas dobles a los nombres de los objetos. Estas comillas pueden provocar todo tipo de problemas después de la migración.
Le recomendamos que quite todas las comillas que rodean los nombres de los objetos de las instrucciones del lenguaje de definición de datos (DDL) antes de crear los objetos en PostgreSQL.
Sintaxis para crear tablas
Cuando se convierten tablas de Oracle a tipos de datos de PostgreSQL, el primer paso es extraer las instrucciones de creación de tablas de Oracle de la base de datos de origen. La siguiente consulta de ejemplo extrae el DDL de la tabla de ubicaciones del esquema HR:
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE', 'LOCATIONS') FROM DUAL;
CREATE TABLE "HR"."LOCATIONS"
( "LOCATION_ID" NUMBER(4,0),
"STREET_ADDRESS" VARCHAR2(40),
"POSTAL_CODE" VARCHAR2(12),
"CITY" VARCHAR2(30) CONSTRAINT "LOC_CITY_NN" NOT NULL ENABLE,
"STATE_PROVINCE" VARCHAR2(25),
"COUNTRY_ID" CHAR(2),
CONSTRAINT "LOC_ID_PK" PRIMARY KEY ("LOCATION_ID")
...
CONSTRAINT "LOC_C_ID_FK" FOREIGN KEY ("COUNTRY_ID")
REFERENCES "HR"."COUNTRIES" ("COUNTRY_ID") ENABLE
La salida completa incluye elementos de almacenamiento, índices e información de espacio de tabla, que se han omitido porque estos elementos adicionales no son compatibles con la instrucción CREATE TABLE
de PostgreSQL.
Una vez que se haya extraído el DDL, quita las comillas que rodean los nombres y realiza la conversión de la tabla según la tabla de conversión de tipos de datos de Oracle a PostgreSQL. Comprueba el tipo de datos de cada columna para ver si se puede convertir tal cual o, si no es compatible, elige otro tipo de datos según la tabla de conversión. Por ejemplo, a continuación se muestra el DDL convertido de la tabla locations.
CREATE TABLE HR.LOCATIONS (
LOCATION_ID NUMERIC(4,0),
STREET_ADDRESS VARCHAR(40),
POSTAL_CODE VARCHAR(12),
CITY VARCHAR(30) CONSTRAINT LOC_CITY_NN NOT NULL,
STATE_PROVINCE VARCHAR(25),
COUNTRY_ID CHAR(2),
CONSTRAINT LOC_ID_PK PRIMARY KEY (LOCATION_ID),
CONSTRAINT LOC_C_ID_FK FOREIGN KEY (COUNTRY_ID)
REFERENCES HR.COUNTRIES (COUNTRY_ID)
)
Crear tabla como selección (CTAS)
La instrucción CREATE TABLE AS SELECT
(CTAS) se usa para crear una tabla a partir de otra. Ten en cuenta que solo se copian los nombres y los tipos de datos de las columnas, pero no las restricciones ni los índices. PostgreSQL admite el estándar ANSI SQL para la funcionalidad CTAS y es compatible con la instrucción CTAS de Oracle.
Columnas invisibles de Oracle 12c
PostgreSQL no admite columnas invisibles. Para solucionar este problema, crea una vista que contenga solo las columnas visibles.
Restricciones de tabla
Oracle ofrece seis tipos de restricciones de tabla que se pueden definir al crear una tabla o después de crearla mediante el comando ALTER TABLE
. Los tipos de restricciones de Oracle son PRIMARY KEY
, FOREIGN KEY
, UNIQUE
, CHECK
, NOT
NULL
y REF
. Además, Oracle permite al usuario controlar el estado de una restricción mediante las siguientes opciones:
INITIALLY IMMEDIATE
: comprueba la restricción al final de cada instrucción SQL posterior (el estado predeterminado).DEFERRABLE/NOT DEFERRABLE
: permite usar la cláusulaSET CONSTRAINT
en las transacciones posteriores hasta que se envíe una instrucciónCOMMIT
INITIALLY DEFERRED
: comprueba la restricción al final de las transacciones posteriores.VALIDATE/NO VALIDATE
: comprueba (o no comprueba deliberadamente) si hay errores en las filas nuevas o modificadas. Estos parámetros dependen de si la restricción esENABLED
oDISABLED
.ENABLED/DISABLED
: especifica si la restricción debe aplicarse después de la creación (ENABLED
de forma predeterminada).
PostgreSQL también admite seis tipos de restricciones de tabla: PRIMARY KEY
, FOREIGN KEY
, UNIQUE
, CHECK
, NOT NULL
y EXCLUDE
. Sin embargo, hay algunas diferencias notables entre los tipos de restricciones de Oracle y PostgreSQL, entre las que se incluyen las siguientes:
- PostgreSQL no admite la restricción
REF
de Oracle. - PostgreSQL no crea automáticamente un índice en las columnas de referencia de una restricción de clave externa. Si se necesita un índice, se debe incluir una instrucción
CREATE INDEX
independiente en las columnas de referencia. - PostgreSQL no admite la cláusula
ON DELETE SET NULL
de Oracle. Esta cláusula indica a Oracle que asigne el valorNULL
a los valores dependientes de las tablas secundarias cuando se elimine el registro de la tabla principal. - No se admiten restricciones en
VIEWS
, exceptoCHECK OPTION
. - PostgreSQL no admite la inhabilitación de restricciones. PostgreSQL admite la opción
NOT VALID
cuando se añade una clave externa o una restricción de comprobación con una instrucciónALTER TABLE
. Esta opción indica a PostgreSQL que omita las comprobaciones de integridad referencial en los registros de la tabla secundaria.
En la siguiente tabla se resumen las principales diferencias entre los tipos de restricciones de Oracle y PostgreSQL:
Tipo de restricción de Oracle | Compatibilidad con Cloud SQL para PostgreSQL | Equivalente de Cloud SQL para PostgreSQL |
---|---|---|
PRIMARY KEY |
Sí | PRIMARY KEY |
FOREIGN KEY |
Sí | Usa la misma sintaxis ANSI SQL que Oracle. Usa la cláusula ON DELETE para gestionar los casos de eliminación de registros principales FOREIGN
KEY . PostgreSQL ofrece tres opciones para gestionar los casos en los que se eliminan datos de la tabla principal y una tabla secundaria hace referencia a una restricción FOREIGN KEY :
PostgreSQL no admite la cláusula ON DELETE SET NULL
de Oracle. Usa la cláusula ON UPDATE para gestionar los casos de actualizaciones de registros principales de FOREIGN
KEY .PostgreSQL ofrece tres opciones para gestionar los FOREIGN KEY
eventos de actualización de restricciones:
PostgreSQL no crea automáticamente un índice en las columnas de referencia de una restricción de clave externa. |
UNIQUE |
Sí | Crea un índice UNIQUE de forma predeterminada. |
CHECK |
Sí | CHECK |
NOT NULL |
Sí | NOT NULL |
REF |
No | No es compatible. |
DEFERRABLE/NOT DEFERRABLE |
Sí | DEFERRABLE/NOT DEFERRABLE |
INITIALLY IMMEDIATE |
Sí | INITIALLY IMMEDIATE |
INITIALLY DEFERRED |
Sí | INITIALLY DEFERRED |
VALIDATE/NO VALIDATE |
No | No es compatible. |
ENABLE/DISABLE |
No | Esta opción está habilitada de forma predeterminada. Usa la opción NOT VALID cuando se añada una nueva clave externa o una restricción CHECK a la tabla mediante una instrucción ALTER
TABLE para omitir las comprobaciones de integridad referencial en los registros. |
Restricción en las VISTAS | No | No se admite, excepto VIEW WITH CHECK OPTION . |
Metadatos de restricciones | Oracle | DBA_CONSTRAINTS |
PostgreSQL | INFORMATION_SCHEMA.TABLE_CONSTRAINTS |
Columnas virtuales y generadas
Las columnas virtuales de Oracle se basan en los resultados de los cálculos de otras columnas. Aparecen como columnas normales, pero sus valores se derivan de un cálculo que realiza sobre la marcha el motor de la base de datos Oracle y no se almacenan en la base de datos. Las columnas virtuales se pueden usar con restricciones, índices, particiones de tablas y claves externas, pero no se pueden manipular mediante operaciones del lenguaje de manipulación de datos (DML).
Las columnas generadas de PostgreSQL son comparables a las columnas virtuales de Oracle en cuanto a funcionalidad. Sin embargo, a diferencia de Oracle, las columnas generadas en PostgreSQL se almacenan y debe especificar un tipo de datos para cada columna generada, lo que significa que ocupan espacio de almacenamiento como si fueran columnas normales.
Ejemplo de columna virtual en Oracle:
SQL> CREATE TABLE PRODUCTS ( PRODUCT_ID INT PRIMARY KEY, PRODUCT_TYPE VARCHAR2(100) NOT NULL, PRODUCT_PRICE NUMBER(6,2) NOT NULL, PRICE_WITH_TAX AS (ROUND(PRODUCT_PRICE * 1.01, 2)) ); SQL> INSERT INTO PRODUCTS(PRODUCT_ID, PRODUCT_TYPE, PRODUCT_PRICE) VALUES(1, 'A', 99.99); SQL> SELECT * FROM PRODUCTS;
PRODUCT_ID PRODUCT_TYPE PRODUCT_PRICE PRICE_WITH_TAX ---------- -------------------- ------------- -------------- 1 A 99.99 100.99
Ejemplo equivalente en PostgreSQL:
postgres=> CREATE TABLE PRODUCTS ( postgres(> PRODUCT_ID INT PRIMARY KEY, postgres(> PRODUCT_TYPE VARCHAR(100) NOT NULL, postgres(> PRODUCT_PRICE NUMERIC(6,2) NOT NULL, postgres(> PRICE_WITH_TAX NUMERIC GENERATED ALWAYS AS (ROUND(PRODUCT_PRICE * 1.01, 2)) STORED postgres(> ); postgres=> INSERT INTO PRODUCTS(PRODUCT_ID, PRODUCT_TYPE, PRODUCT_PRICE) VALUES(1, 'A', 99.99); postgres=> SELECT * FROM PRODUCTS;
product_id | product_type | product_price | price_with_tax ------------+--------------+---------------+---------------- 1 | A | 99.99 | 100.99 (1 row)
Índices de tablas
Oracle y PostgreSQL ofrecen varios algoritmos de indexación y tipos de índices que se pueden usar en diversas aplicaciones. A continuación, se muestra una lista de los algoritmos de indexación disponibles en PostgreSQL:
Algoritmo de índice | Descripción |
---|---|
Árbol B |
|
Hash |
|
GIN |
|
GiST |
|
SP-GiST |
|
BRIN |
|
En la siguiente tabla se comparan los tipos de índice de Oracle y PostgreSQL:
Índice de Oracle | Descripción | Compatible con PostgreSQL | Equivalente de PostgreSQL |
---|---|---|---|
Índice de mapa de bits | Almacena un mapa de bits por cada clave de índice, lo que resulta ideal para proporcionar una recuperación de datos rápida para cargas de trabajo de OLAP. | No | N/A |
Índice de árbol B | Es el tipo de índice más habitual, se adapta bien a diversas cargas de trabajo y se puede configurar en orden ASC|DESC . |
Sí | Índice de árbol B |
Índice compuesto | Se crea en dos o más columnas para mejorar el rendimiento de la recuperación de datos. El orden de las columnas dentro del índice determina la ruta de acceso. | Sí | Índices de varias columnas Se pueden especificar hasta 32 columnas al crear un índice de varias columnas. |
Índice basado en funciones | Almacena el resultado de una función aplicada a los valores de una columna de una tabla. | Sí | Índices en expresiones |
Índice único | Un índice de árbol B que aplica una restricción UNIQUE a los valores indexados de cada columna. |
Sí | Índice único |
Índice de dominio de la aplicación | Adecuado para indexar datos no relacionales, como datos de audio o vídeo, datos LOB y otros tipos no textuales. | No | N/D |
Índice invisible | Función de Oracle que te permite gestionar, mantener y probar índices sin afectar a la toma de decisiones del optimizador. | No | Como solución alternativa, puedes crear un índice adicional en una réplica de lectura para hacer pruebas sin que afecte a la actividad en curso. |
Tabla organizada por índice | Tipo de índice que controla cómo se almacenan los datos a nivel de tabla e índice. | No | PostgreSQL no admite tablas organizadas por índices. La instrucción CLUSTER
indica a PostgreSQL que organice el almacenamiento de la tabla según un índice especificado. Tiene un propósito similar al de la tabla organizada por índice de Oracle. Sin embargo, la agrupación en clústeres es una operación que se realiza una sola vez y PostgreSQL no mantiene la estructura de la tabla en las actualizaciones posteriores. Se necesita un clúster manual y periódico. |
Índice local y global | Se usa para indexar tablas con particiones en una base de datos de Oracle. Cada índice se define como LOCAL o GLOBAL . |
No | Los índices de trabajo de las particiones de PostgreSQL tienen la misma función que los índices locales de Oracle (es decir, el índice se define a nivel de partición y no se admite el nivel global). |
Índices parciales de tablas con particiones (Oracle 12c) | Crea un índice en un subconjunto de las particiones de una tabla. Admite LOCAL y GLOBAL . |
Sí | La partición en PostgreSQL funciona adjuntando tablas secundarias a una tabla principal. Solo se pueden crear índices en un subconjunto de tablas secundarias. |
CREATE/DROP INDEX |
Comando usado para crear y eliminar índices. | Sí | PostgreSQL admite el comando CREATE INDEX . También admite
ALTER TABLE tableName ADD INDEX indexName
columnName |
ALTER INDEX ... REBUILD |
Recompila el índice, lo que puede provocar un bloqueo exclusivo en la tabla indexada. | Requiere una sintaxis diferente | PostgreSQL admite la reconstrucción de índices mediante la instrucción REINDEX . La tabla se bloquea para las escrituras durante esta operación y solo se permiten lecturas. |
ALTER INDEX ... REBUILD ONLINE |
Recompila un índice sin crear un bloqueo exclusivo en la tabla. | Requiere una sintaxis diferente | PostgreSQL admite la reconstrucción simultánea de índices mediante la instrucción REINDEX TABLE
CONCURRENTLY . En este modo, PostgreSQL intenta volver a crear los índices con un bloqueo mínimo, pero puede tardar más tiempo y consumir más recursos en completar la recompilación. |
Compresión de índices | Una función para reducir el tamaño físico del índice. | No | N/A |
Asignar índice a un espacio de tabla |
Crea un tablespace de índice que se puede almacenar en un disco independiente de los datos de la tabla para reducir los cuellos de botella de E/S de disco. | No | Aunque PostgreSQL permite crear un índice en un espacio de tablas definido por el usuario, no puedes crear espacios de tablas en Cloud SQL para PostgreSQL, y el índice se debe crear en el espacio de tablas predeterminado. |
Indexa metadatos (tablas o vistas) | Oracle | DBA_INDEXES |
|
PostgreSQL | pg_catalog.pg_index |
Consideraciones sobre la conversión de índices
En la mayoría de los casos, los índices de Oracle se pueden convertir en índices de árbol B de PostgreSQL, ya que este tipo de índice es el más utilizado.
Al igual que en una base de datos Oracle, se crea automáticamente un índice en los PRIMARY KEY
campos de una tabla. Del mismo modo, se crea automáticamente un índice UNIQUE
en los campos que tienen una restricción UNIQUE
. Además, los índices secundarios se crean mediante la instrucción CREATE INDEX
estándar.
En el siguiente ejemplo se muestra cómo se puede convertir una tabla de Oracle con varios campos indexados a PostgreSQL:
SQL> CREATE TABLE ORA_IDX_TO_PG (
col1 INT PRIMARY KEY,
col2 VARCHAR2(60),
col3 DATE,
col4 CLOB,
col5 VARCHAR2(20)
);
-- Single-field index
SQL> CREATE INDEX idx_col2 ON ora_idx_to_pg(col2);
-- Composite index
SQL> CREATE INDEX idx_cols3_2 ON ora_idx_to_pg(col3 DESC, col2);
-- Unique index
SQL> CREATE UNIQUE INDEX idx_col3_uni ON ora_idx_to_pg(col3);
-- Function-based index
SQL> CREATE INDEX idx_func_col3 ON
ora_idx_to_pg(EXTRACT(MONTH FROM col3));
-- CLOB index
SQL> CREATE INDEX idx_col4 ON
ora_idx_to_pg(col4) INDEXTYPE IS CTXSYS.CONTEXT;
-- Invisible index
SQL> CREATE INDEX idx_col5_inv ON
ora_idx_to_pg(col5) INVISIBLE;
-- Drop index
SQL> DROP INDEX idx_col5_inv;
postgres=> CREATE TABLE ORA_IDX_TO_PG (
postgres(> col1 INT PRIMARY KEY,
postgres(> col2 VARCHAR(60),
postgres(> col3 DATE,
postgres(> col4 TEXT,
postgres(> col5 VARCHAR(20)
postgres(> );
-- Single index (supported)
postgres=> CREATE INDEX idx_col2 ON ora_idx_to_pg(col2);
-- Composite index (supported)
postgres=> CREATE INDEX idx_cols3_2 ON ora_idx_to_pg(col3 DESC, col2);
-- Unique index (supported)
postgres=> CREATE UNIQUE INDEX idx_col3_uni ON ora_idx_to_pg(COL3);
-- Function-based index (supported)
postgres=> CREATE INDEX idx_func_col3 ON
postgres-> ora_idx_to_pg(EXTRACT(MONTH FROM col3));
-- CLOB (Supported, but requires different syntax. See Full Text Search for details)
postgres=> CREATE INDEX idx_col4 ON ora_idx_to_pg
postgres-> USING GIN (to_tsvector('english', col4));
-- Invisible index (not supported)
-- Optional - create the index as a B-tree index
postgres=> CREATE INDEX idx_col5 ON ora_idx_to_pg(col5);
-- Drop index
postgres=> DROP INDEX idx_col2;
SQL> SELECT ui.table_name,
ui.index_name,
ui.index_type,
ic.column_name
FROM user_indexes ui JOIN user_ind_columns ic
ON ui.index_name = ic.index_name
WHERE ui.table_name = 'ORA_IDX_TO_PG'
ORDER BY 4;
postgres=> select distinct
postgres-> t.relname as table_name,
postgres-> i.relname as index_name,
postgres-> pg_get_indexdef(ix.indexrelid) index_definition
postgres-> from
postgres-> pg_class t,
postgres-> pg_class i,
postgres-> pg_index ix
postgres-> where
postgres-> t.oid = ix.indrelid
postgres-> and i.oid = ix.indexrelid
postgres-> and t.relname = 'ora_idx_to_pg'
postgres-> order by
postgres-> t.relname,
postgres-> i.relname;
-- OR Use psql \d command:
postgres=> \d ora_idx_to_pg
Table "public.ora_idx_to_pg"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
col1 | integer | | not null |
col2 | character varying(60) | | |
col3 | date | | |
col4 | text | | |
col5 | character varying(20) | | |
Indexes:
"ora_idx_to_pg_pkey" PRIMARY KEY, btree (col1)
"idx_col2" btree (col2)
"idx_col4" gin (to_tsvector('english'::regconfig, col4))
"idx_col5" btree (col5)
"idx_cols3_2" btree (col3 DESC, col2)
"idx_func_col3" btree (date_part('month'::text, col3))
postgres=>
Particiones de tablas
Tanto Oracle como PostgreSQL ofrecen funciones de partición para dividir tablas grandes. Para ello, se segmenta físicamente una tabla en partes más pequeñas, donde cada parte contiene un subconjunto horizontal de las filas. La tabla con particiones se denomina tabla principal y sus filas se almacenan físicamente en sus particiones. Aunque no todos los tipos de partición de Oracle son compatibles con PostgreSQL, PostgreSQL sí admite los más comunes.
En las siguientes secciones se describen los tipos de particiones admitidos por PostgreSQL y se ilustra cada uno con un ejemplo de cómo crear las particiones que corresponden a ese tipo.
Partición por RANGE
Este tipo de partición asigna filas a particiones en función de los valores de las columnas que se encuentran dentro de un intervalo determinado. Cada partición contiene filas en las que el valor de la expresión de partición se encuentra dentro de un intervalo determinado. Es importante tener en cuenta que los intervalos no se solapan entre particiones.
Ejemplo
CREATE TABLE employees (
empid INT,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE,
separated DATE,
job_code INT,
store_id INT)
PARTITION BY RANGE (store_id);
CREATE TABLE employees_p0 PARTITION OF employees
FOR VALUES FROM (MINVALUE) TO (6);
CREATE TABLE employees_p1 PARTITION OF employees
FOR VALUES FROM (6) TO (11);
CREATE TABLE employees_p2 PARTITION OF employees
FOR VALUES FROM (11) TO (16);
CREATE TABLE employees_p3 PARTITION OF employees
FOR VALUES FROM (16) TO (21);
Particiones LIST
Al igual que la partición RANGE
, la partición LIST
asigna filas a particiones en función de los valores de las columnas que se encuentren dentro de un conjunto de valores predefinido. Los valores de clave que aparecen en cada partición se enumeran explícitamente para las particiones LIST
.
Ejemplo
CREATE TABLE employees (
empid INT,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE,
separated DATE,
job_code INT,
store_id INT)
PARTITION BY LIST (store_id);
CREATE TABLE employees_pNorth PARTITION OF employees
FOR VALUES IN (3,5,6);
CREATE TABLE employees_pEast PARTITION OF employees
FOR VALUES IN (1,2,10);
CREATE TABLE employees_pWest PARTITION OF employees
FOR VALUES IN (4,12,13);
CREATE TABLE employees_pCnrl PARTITION OF employees
FOR VALUES IN (7,8,15);
Particiones HASH
La partición HASH
es la más adecuada cuando el objetivo es conseguir una distribución uniforme de los datos entre todas las particiones. Se asignan un valor de columna (o una expresión basada en un valor de columna que se va a cifrar con hash) y el valor de la fila a la partición que corresponde a ese valor de hash. Los valores hash deben asignarse de forma única a las particiones y todos los valores insertados deben asignarse a exactamente una partición.
Ejemplo
CREATE TABLE employees (
empid INT,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE,
separated DATE,
job_code INT,
store_id INT)
PARTITION BY HASH (date_part('year', hired));
CREATE TABLE employees_p0 PARTITION OF employees
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE employees_p1 PARTITION OF employees
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE employees_p2 PARTITION OF employees
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE employees_p3 PARTITION OF employees
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
Particiones multinivel
La creación de particiones de varios niveles es un método para crear una jerarquía de particiones de una sola tabla. Cada partición se divide en varias particiones diferentes. El número de subparticiones puede variar de una partición a otra.
Ejemplo
CREATE TABLE sales (
Saleid INT,
sale_date DATE,
cust_code VARCHAR(15),
income DECIMAL(8,2))
PARTITION BY RANGE(date_part('year', sale_date));
CREATE TABLE sales_2019 PARTITION OF sales
FOR VALUES FROM (2019) TO (2020)
PARTITION BY RANGE(date_part('month', sale_date));
CREATE TABLE sales_2019_q1 PARTITION OF sales_2019
FOR VALUES FROM (1) TO (4);
CREATE TABLE sales_2019_q2 PARTITION OF sales_2019
FOR VALUES FROM (4) TO (7);
CREATE TABLE sales_2019_q3 PARTITION OF sales_2019
FOR VALUES FROM (7) TO (10);
CREATE TABLE sales_2019_q4 PARTITION OF sales_2019
FOR VALUES FROM (10) TO (13);
CREATE TABLE sales_2020 PARTITION OF sales
FOR VALUES FROM (2020) TO (2021)
PARTITION BY RANGE(date_part('month', sale_date));
CREATE TABLE sales_2020_q1 PARTITION OF sales_2020
FOR VALUES FROM (1) TO (4);
CREATE TABLE sales_2020_q2 PARTITION OF sales_2020
FOR VALUES FROM (4) TO (7);
CREATE TABLE sales_2020_h2 PARTITION OF sales_2020
FOR VALUES FROM (7) TO (13);
Adjuntar o separar particiones
En PostgreSQL, las particiones se pueden añadir o quitar de la tabla principal. Una partición que se ha separado se puede volver a adjuntar a la misma tabla más adelante. Además, se pueden especificar nuevas condiciones de partición al volver a adjuntar la partición, lo que permite ajustar los límites de la partición.
Ejemplo
CREATE TABLE employees (
empid INT,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE,
separated DATE,
job_code INT,
store_id INT)
PARTITION BY RANGE (date_part('year', hired));
CREATE TABLE employees_p0 PARTITION OF employees
FOR VALUES FROM (2010) TO (2015);
CREATE TABLE employees_p1 PARTITION OF employees
FOR VALUES FROM (2015) TO (2020);
-- changing partition boundaries
BEGIN TRANSACTION;
ALTER TABLE employees DETACH PARTITION employees_p1;
ALTER TABLE employees ATTACH PARTITION employees_p1 FOR VALUES FROM (2015) TO (2022);
COMMIT TRANSACTION;
En la siguiente tabla se describe en qué casos los tipos de partición de Oracle y Cloud SQL para PostgreSQL son equivalentes y en qué casos se recomienda una conversión:
Tipo de partición de Oracle | Compatible con PostgreSQL | Implementación de PostgreSQL |
---|---|---|
RANGE particiones |
Sí | PARTITION BY RANGE |
LIST particiones |
Sí | PARTITION BY LIST |
HASH particiones |
Sí | PARTITION BY HASH |
SUB-PARTITIONING |
Sí | Particiones multinivel |
Particiones de intervalos | No | No compatible |
Asesor de particiones | No | No compatible |
Partición de preferencias | No | No compatible |
Partición virtual basada en columnas | No | Para solucionar este problema, puedes crear particiones directamente con la expresión de columna virtual:
|
Partición automática de listas | No | No compatible |
Particiones |
No | Para solucionar este problema, puedes separar o adjuntar particiones de la tabla para ajustar los límites de las particiones. |
Intercambiar particiones | Sí | DETACH / ATTACH PARTITION |
Particiones de varios tipos (particiones compuestas) | Sí | Particiones multinivel |
Metadatos de particiones | Oracle | DBA_TAB_PARTITIONS |
PostgreSQL | pg_catalog.pg_class |
En el siguiente ejemplo se muestra una comparación de la creación de particiones de tabla en ambas plataformas. Ten en cuenta que PostgreSQL no admite
hacer referencia a un tablespace en la cláusula PARTITIONS
del comando CREATE TABLE
.
Implementación de Oracle
CREATE TABLE employees (
empid NUMBER,
fname VARCHAR2(30),
lname VARCHAR2(30),
hired DATE,
separated DATE,
job_code NUMBER,
store_id NUMBER)
PARTITION BY LIST (store_id) (
PARTITION employees_pNorth VALUES (3,5,6) TABLESPACE users,
PARTITION employees_pEast VALUES (1,2,10) TABLESPACE users,
PARTITION employees_pWest VALUES (4,12,13) TABLESPACE users,
PARTITION employees_pCnrl VALUES (7,8,15) TABLESPACE users
);
Implementación de PostgreSQL
CREATE TABLE employees (
empid INT,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE,
separated DATE,
job_code INT,
store_id INT)
PARTITION BY LIST (store_id);
CREATE TABLE employees_pNorth PARTITION OF employees
FOR VALUES IN (3,5,6);
CREATE TABLE employees_pEast PARTITION OF employees
FOR VALUES IN (1,2,10);
CREATE TABLE employees_pWest PARTITION OF employees
FOR VALUES IN (4,12,13);
CREATE TABLE employees_pCnrl PARTITION OF employees
FOR VALUES IN (7,8,15);
Tablas temporales
En una base de datos de Oracle, las tablas temporales se denominan GLOBAL TEMPORARY TABLES
, mientras que en PostgreSQL se conocen simplemente como tablas temporales. La funcionalidad básica de una tabla temporal es idéntica en ambas plataformas. Sin embargo, hay algunas diferencias notables:
- Oracle almacena la estructura de la tabla temporal para que se pueda usar repetidamente incluso después de reiniciar la base de datos, mientras que PostgreSQL almacena la tabla temporal solo durante la sesión.
- Diferentes usuarios pueden acceder a una tabla temporal de una base de datos Oracle si tienen los permisos adecuados. Por el contrario, solo se puede acceder a una tabla temporal en PostgreSQL durante la sesión en la que se creó, a menos que se haga referencia a la tabla temporal con nombres calificados por el esquema.
- En una base de datos Oracle, se distingue entre las tablas
GLOBAL
yLOCAL
temporales que especifican si el contenido de la tabla es global o específico de la sesión. En PostgreSQL, se admiten las palabras claveGLOBAL
yLOCAL
por motivos de compatibilidad, pero no tienen ningún efecto en la visibilidad de los datos. - Si se omite la cláusula
ON COMMIT
al crear una tabla temporal, el comportamiento predeterminado en Oracle Database esON COMMIT DELETE ROWS
, lo que significa que Oracle trunca la tabla temporal después de cada confirmación. Por el contrario, en PostgreSQL, el comportamiento predeterminado es conservar las filas de la tabla temporal después de cada confirmación.
En la siguiente tabla se destacan las diferencias entre las tablas temporales de Oracle y Cloud SQL para PostgreSQL.
Función de tabla temporal | Implementación de Oracle | Implementación de PostgreSQL |
---|---|---|
Sintaxis | CREATE GLOBAL TEMPORARY TABLE |
CREATE TEMPORARY TABLE |
Funciones de accesibilidad | Se puede acceder desde varias sesiones | Solo se puede acceder desde la sesión del creador, a menos que se haga referencia a ellos con nombres cualificados por el esquema. |
Compatibilidad con índices | Sí | Sí |
Compatibilidad con claves externas | Sí | Sí |
Conservar DDL | Sí | No |
Acción predeterminada de ON COMMIT |
Se eliminan los registros | Los registros se conservan |
ON COMMIT PRESERVE ROWS |
Sí | Sí |
ON COMMIT DELETE ROWS |
Sí | Sí |
ON COMMIT DROP |
No | Sí |
ALTER TABLE Asistencia |
Sí | Sí |
Recogida de estadísticas | DBMS_STATS.GATHER_TABLE_STATS |
ANALYZE |
Oracle 12c GLOBAL_TEMP_ TABLE_STATS |
DBMS_STATS.SET_TABLE_PREFS |
ANALYZE |
Columnas no utilizadas
La función de Oracle que permite marcar columnas específicas como UNUSED
se suele usar para eliminar columnas de tablas sin eliminar físicamente los datos de las columnas. Esto se hace para evitar las posibles cargas elevadas que se producen al eliminar columnas de tablas grandes.
En PostgreSQL, al eliminar una columna grande, no se quitan los datos de la columna del almacenamiento físico, por lo que es una operación rápida incluso en tablas grandes. No es necesario marcar una columna como UNUSED
, como en una base de datos Oracle. El espacio ocupado por la columna eliminada se recupera mediante nuevas instrucciones DML o durante una operación posterior de VACUUM
.
Tablas de solo lectura
Las tablas de solo lectura son una función de Oracle que marca las tablas como de solo lectura mediante el comando ALTER TABLE
. En Oracle 12c R2, esta función también está disponible para tablas con particiones y subparticiones. PostgreSQL no ofrece una función equivalente, pero hay dos posibles soluciones alternativas:
- Concede el permiso
SELECT
en las tablas a usuarios específicos. Ten en cuenta que esto no impide que el propietario de la tabla realice operaciones de DML en sus tablas. - Crea una réplica de lectura de Cloud SQL para PostgreSQL y dirige a los usuarios a las tablas de réplica, que son de solo lectura. Esta solución requiere añadir una instancia de réplica de lectura a una instancia de Cloud SQL para PostgreSQL.
Crea un activador de base de datos que genere excepciones en las instrucciones DML. Por ejemplo:
-- Define trigger function CREATE OR REPLACE FUNCTION raise_readonly_exception() RETURNS TRIGGER AS $$ BEGIN RAISE EXCEPTION 'Table is readonly!'; RETURN NULL; END; $$ LANGUAGE 'plpgsql'; -- Fire trigger when DML statements is executed on read only table CREATE TRIGGER myTable_readonly_trigger BEFORE INSERT OR UPDATE OR DELETE OR TRUNCATE ON myTable FOR EACH STATEMENT EXECUTE PROCEDURE raise_readonly_exception(); -- Testing the trigger postgres=> INSERT INTO myTable (id) VALUES (1); ERROR: Table is readonly! CONTEXT: PL/pgSQL function raise_readonly_exception() line 3 at RAISE postgres=>
Conjuntos de caracteres
Tanto Oracle como PostgreSQL admiten una amplia variedad de conjuntos de caracteres, ordenaciones y Unicode, incluida la compatibilidad con idiomas de un solo byte y de varios bytes. Además, las bases de datos PostgreSQL que residen en la misma instancia se pueden configurar con conjuntos de caracteres distintos. Consulta la lista de conjuntos de caracteres admitidos en PostgreSQL.
En Oracle Database, los conjuntos de caracteres se especifican a nivel de base de datos (Oracle 12g R1 o versiones anteriores) o a nivel de base de datos conectable (Oracle 12g R2 o versiones posteriores). En PostgreSQL, se especifica un conjunto de caracteres predeterminado cuando se crea una instancia de Cloud SQL para PostgreSQL. Cada base de datos creada en esa instancia se puede crear con un conjunto de caracteres diferente. El orden y la clasificación de los caracteres se pueden especificar por columna de la tabla.
Ejemplo
-- Create a database using UTF-8 character set and ja_JP.UTF collation
postgres=> CREATE DATABASE jpdb WITH ENCODING 'UTF8' LC_COLLATE='ja_JP.UTF8' LC_CTYPE='ja_JP.UTF8' TEMPLATE=template0;
-- Query the character set and collation settings of all databases
postgres=> SELECT datname AS DATABASE_NAME, datcollate AS LC_COLLATE, datctype AS LC_CTYPE from pg_database;
database_name | lc_collate | lc_ctype
---------------+------------+------------
cloudsqladmin | en_US.UTF8 | en_US.UTF8
template0 | en_US.UTF8 | en_US.UTF8
template1 | en_US.UTF8 | en_US.UTF8
postgres | en_US.UTF8 | en_US.UTF8
jpdb | ja_JP.UTF8 | ja_JP.UTF8
(5 rows)
-- Alternatively, use psql \l command to query the database settings
postgres=> \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
---------------+-------------------+----------+------------+------------+-----------------------------------------
cloudsqladmin | cloudsqladmin | UTF8 | en_US.UTF8 | en_US.UTF8 |
postgres | cloudsqlsuperuser | UTF8 | en_US.UTF8 | en_US.UTF8 | =Tc/cloudsqlsuperuser +
| | | | | cloudsqlsuperuser=CTc/cloudsqlsuperuser+
| | | | | testuser=CTc/cloudsqlsuperuser
template0 | cloudsqladmin | UTF8 | en_US.UTF8 | en_US.UTF8 | =c/cloudsqladmin +
| | | | | cloudsqladmin=CTc/cloudsqladmin
template1 | cloudsqlsuperuser | UTF8 | en_US.UTF8 | en_US.UTF8 | =c/cloudsqlsuperuser +
| | | | | cloudsqlsuperuser=CTc/cloudsqlsuperuser
-- Specifying column level collation
postgres=> CREATE TABLE test1 (
postgres(> a text COLLATE "de_DE",
postgres(> b text COLLATE "es_ES"
postgres(> );
Vistas
PostgreSQL admite vistas simples y complejas. En cuanto a las opciones de creación de vistas, hay algunas diferencias entre Oracle y PostgreSQL. En la siguiente tabla se destacan estas diferencias.
Función de vista de Oracle | Descripción | Compatibilidad con Cloud SQL para PostgreSQL | Consideraciones sobre las conversiones |
---|---|---|---|
FORCE |
Crea una vista sin verificar si existen las tablas o vistas de origen. | No | No hay ninguna opción equivalente disponible. |
CREATE OR REPLACE |
Crea una vista que no exista o sobrescribe una que ya tengas. | Sí | PostgreSQL admite el comando CREATE OR REPLACE para las vistas. |
WITH CHECK OPTION |
Especifica el nivel de cumplimiento al realizar operaciones de DML en la vista. | Sí | El valor predeterminado es CASCADED , lo que provoca que las vistas a las que se hace referencia también se evalúen.La palabra clave LOCAL hace que solo se evalúe la vista actual. |
WITH READ-ONLY |
Permite solo operaciones de lectura en la vista. Las operaciones de DML están prohibidas. | No | Una solución alternativa es conceder privilegios SELECT en la vista a todos los usuarios. |
VISIBLE | INVISIBLE (Oracle 12c) |
Especifica si una columna basada en la vista es visible o invisible para el usuario. | No | Crea el VIEW con las columnas obligatorias. |
En el siguiente ejemplo de conversión se muestra cómo convertir de Oracle a Cloud SQL PostgreSQL para vistas.
-- Create view to retrieve employees from department 100 using the WITH CHECK -- OPTION option
SQL> CREATE OR REPLACE FORCE VIEW vw_emp_dept100
AS
SELECT EMPLOYEE_ID,
FIRST_NAME,
LAST_NAME,
SALARY,
DEPARTMENT_ID
FROM EMPLOYEES
WHERE DEPARTMENT_ID=100
WITH CHECK OPTION;
-- Perform an UPDATE operation on the VIEW
SQL> UPDATE vw_emp_dept100
SET salary=salary+1000;
postgres=> CREATE OR REPLACE VIEW vw_emp_dept100
postgres-> AS
postgres-> SELECT EMPLOYEE_ID,
postgres-> FIRST_NAME,
postgres-> LAST_NAME,
postgres-> SALARY,
postgres-> DEPARTMENT_ID
postgres-> FROM EMPLOYEES
postgres-> WHERE DEPARTMENT_ID=100
postgres-> WITH CHECK OPTION;
-- Perform an UPDATE operation on the VIEW
postgres=> UPDATE vw_emp_dept100
postgres-> SET salary=salary+1000;
-- Update one employee department id to 60
postgres=> UPDATE vw_emp_dept100
postgres-> SET DEPARTMENT_ID=60
postgres-> WHERE EMPLOYEE_ID=110;
ERROR: new row violates check option for view "vw_emp_dept100"
DETAIL: Failing row contains (110, John, Chen, JCHEN, 515.124.4269, 1997-09-28, FI_ACCOUNT, 9200.00, null, 108, 60).
Gestión de accesos a la vista:
Los propietarios de una vista deben tener privilegios en las tablas base para crear la vista. El usuario de una vista necesita los permisos SELECT
adecuados en la vista.
También necesitan los permisos INSERT
, UPDATE
y DELETE
adecuados en la vista al realizar operaciones de DML a través de ella. En ambos casos, los usuarios no necesitan permisos en las tablas subyacentes.
Siguientes pasos
- Consulta más información sobre las cuentas de usuario de PostgreSQL.
- Consulta arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Centro de arquitectura de Cloud.