Conversión de sintaxis y funciones comunes mediante el complemento sql_dialect de la base de datos
sql_dialect es un complemento de dialecto SQL para bases de datos de DWS. Se utiliza para convertir sintaxis y funciones comunes entre diferentes sistemas de bases de datos, como MySQL, PostgreSQL, Oracle y SQL Server.
Precauciones
- Las funciones del complemento de dialecto tienen una prioridad más alta que las del kernel de la base de datos, lo que ayuda a resolver conflictos con el kernel.
- El complemento de dialecto se puede vincular a cada base de datos de forma independiente. No está asociado con el parámetro DBCOMPATIBILITY seleccionado durante la ejecución de CREATE DATABASE. Sin embargo, se recomienda que sean consistentes.
- Una vez vinculado el complemento de dialecto, no se puede cambiar. Si desea cambiarlo, debe desinstalarlo y luego vincularlo de nuevo.
Capacidades básicas del complemento sql_dialect
- Admite funciones implementadas mediante SQL simple.
- Admite funciones implementadas mediante PL/pgSQL.
- Admite funciones implementadas mediante C.
- Se puede actualizar y degradar de forma independiente, lo que no tiene relación con la actualización y degradación del kernel de la base de datos.
Estructura del paquete del complemento sql_dialect
1 2 3 4 5 6 7 8 9 10 11 | ├── lib │ └── postgresql │ └── libsql_dialect.so --Plug-in dynamic library file └── share └── postgresql └── extension ├── sql_dialect.control --Plug-in control file ├── sql_dialect_mysql.sql --Object file supported by the MySQL dialect ├── sql_dialect--1.0.0.sql ├── sql_dialect--1.0.0--1.0.1.sql └── sql_dialect--1.0.1--1.0.0.sql |
Uso del complemento sql_dialect
El complemento sql_dialect se puede vincular, desinstalar, actualizar y degradar.
Vinculación de un complemento de dialecto
- Asegúrese de que el complemento sql_dialect se haya instalado correctamente.
- Inicie la ejecución automática del archivo sql_dialect_mysql.sql en el complemento y asegúrese de que las funciones integradas del complemento estén contenidas en el __mysql__ schema. Estas funciones del complemento se pueden utilizar directamente en la sesión actual.
- Ejecute el siguiente comando para vincular el complemento de dialecto:
1ALTER DATABASE database_name SET sql_dialect='mysql';
- Envíe un mensaje para indicar a otras sesiones en línea que utilicen preferentemente las funciones del __mysql__ schema, que tienen una prioridad más alta que las de pg_catalog.
1SELECT pg_reload_conf();
- Utilice el catálogo del sistema PG_EXTENSION para consultar el complemento sql_dialect instalado automáticamente.
1 2 3 4 5
SELECT * FROM pg_extension WHERE extname='sql_dialect'; extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition -------------------+----------+--------------+----------------+------------+-----------+-------------- sql_dialect | 10 | 11 | f | 1.0.0 | | (1 row)
- Utilice el catálogo del sistema PG_NAMESPACE para consultar el esquema creado automáticamente.
1 2 3 4 5
SELECT * FROM pg_namespace WHERE nspname='__dialect_mysql__'; nspname | nspowner | nsptimeline | nspacl | permspace | usedspace | nsptype -------------------+----------+-------------+--------+-----------+-----------+--------- __dialect_mysql__ | 10 | 0 | | -1 | 0 | i (1 row)
- Utilice el catálogo del sistema PG_PROC para consultar las funciones proporcionadas por el complemento de dialecto, que tienen una prioridad más alta que las funciones del kernel de la base de datos. Al utilizar las funciones proporcionadas por el complemento de dialecto, no es necesario especificar un esquema.
1 2 3 4
SELECT proname,nspname,prosrc FROM pg_proc,pg_namespace n WHERE pronamespace=n.oid and nspname='__dialect_mysql__'; proname | nspname | prosrc ---------------+-------------------+--------------------------------------------- rlike | __dialect_mysql__ | select $1 ~ $2
Desinstalación de un complemento de dialecto
Utilice DROP EXTENSION para desinstalar el complemento de dialecto de la base de datos actual.
1 | DROP EXTENSION sql_dialect; |
Actualización o degradación de un complemento de dialecto
- Verifique la versión de la extensión admitida por la base de datos actual.
1SELECT * FROM pg_extension;
- Actualice la extensión a la versión más reciente.
1ALTER EXTENSION extension_name UPDATE;
- Actualice la extensión a una versión especificada.
1ALTER EXTENSION extension_name UPDATE TO 'x.x.x';
Desarrollo de funciones en el complemento sql_dialect
Al aprender los atributos de las funciones y optimizar las funciones, puede mejorar el rendimiento y la compatibilidad de las funciones de los complementos.
Atributos de funciones
Para obtener más información sobre los atributos de las funciones y si las funciones se pueden enviar, consulte CREATE FUNCTION.
Mejora del rendimiento mediante optimización en línea
La optimización en línea es una función del optimizador de consultas de la base de datos y es similar a la capacidad de línea en C++. Si una función de cálculo o conversión corta cumple las condiciones de optimización en línea, el optimizador reemplaza la invocación de la función con una ejecución de expresión. Esta técnica evita la sobrecarga adicional de las invocaciones de funciones y mejora significativamente el rendimiento de la ejecución.
Ejemplo de optimización en línea:
1 2 3 | CREATE FUNCTION func_add_sql(integer, integer) RETURNS integer AS 'select $1 + $2;' LANGUAGE SQL IMMUTABLE; |
Esta función realiza una operación de suma y cumple las condiciones de optimización en línea. El optimizador lo reemplaza con la expresión "$1 + $2".
Como se muestra en el plan de ejecución, el campo Output es la expresión optimizada (a + b) en lugar de una invocación de función.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | EXPLAIN VERBOSE SELECT func_add_sql(a, b) FROM t1; QUERY PLAN ------------------------------------------------------------------------------------------ id | operation | E-rows | E-distinct | E-memory | E-width | E-costs ----+------------------------------+--------+------------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 1 | | | 8 | 9.01 2 | -> Seq Scan on public.t1 | 1 | | 1MB | 8 | 1.01 Targetlist Information (identified by plan id) -------------------------------------------------------- 1 --Streaming (type: GATHER) Output: ((a + b)) Node/s: All datanodes (node_group, bucket:16384) 2 --Seq Scan on public.t1 Output: (a + b) |
Requisitos para las funciones a las que se puede aplicar la optimización en línea
- La función LANGUAGE debe ser SQL.
- La volatilidad de la función no puede ser VOLATILE ni superior a la de la sentencia en el cuerpo de la función. Por ejemplo, si la volatilidad de la función invocada en el cuerpo de la función es STABLE, la volatilidad de la función solo puede ser STABLE y no puede ser IMMUTABLE. La volatilidad incluye IMMUTABLE, STABLE y VOLATILE, en orden descendente.
- El atributo strict de la función debe ser el mismo que el de la función contenida en el cuerpo de la función.
- El cuerpo de la función debe ser una sentencia SELECT simple y no puede contener lógica compleja, como GROUP BY.
- El tipo de retorno de la sentencia en la función debe ser el mismo que el de la función y no puede ser un tipo complejo, como SET o RECORD.
Optimización para parámetros de entrada que contienen NULL
Las funciones cuyos parámetros de entrada contienen NULL devuelven NULL. El atributo STRICT debe definirse explícitamente para dichas funciones para que se pueda reducir la ejecución del cuerpo de la función cuando los parámetros de entrada contengan NULL.
Selección del tipo de función
Para un mejor rendimiento y estabilidad, elija el tipo de función en el siguiente orden: función SQL, función C y función PL/pgSQL.
- Funciones SQL: Elija estas funciones para cálculos simples que cumplan con la función inline y eviten la sobrecarga de invocaciones de funciones.
- Funciones C: Se recomienda definir funciones que contengan más de una sentencia como funciones C.
Debe cumplir estrictamente con las reglas de asignación y liberación de memoria, definir explícitamente el modo de protección FENCED y verificar estrictamente los tipos de parámetros de entrada y valores de retorno para evitar problemas de conjuntos de resultados o excepciones de clúster causadas por inconsistencia de tipos o conversión forzada.
- Funciones PL/pgSQL: Puede elegir estas funciones cuando la lógica es compleja y difícil de implementar mediante funciones C.
Optimización de la configuración de variables GUC dentro de las funciones
Evite configurar variables de entorno dentro de las funciones para evitar sobrecargas innecesarias de comunicación.
1 2 3 4 5 6 7 8 | CREATE OR REPLACE FUNCTION func_increment_plsql(i integer) RETURNS integer SET autoanalyze=off --This does not affect other CNs. AS $$ BEGIN SET autoanalyze=off; --This affects other CNs and incurs communication overhead. RETURN i + 1; END; $$ LANGUAGE plpgsql; |
Optimización de funciones SQL de VOLATILE
Las funciones SQL con el atributo VOLATILE acceden con frecuencia al GTM, lo que genera un rendimiento deficiente y una alta presión sobre el GTM. Evite definir el atributo VOLATILE para las funciones SQL.
Otras notas
- Tipos de datos
Los tipos de parámetros de función y los valores de retorno deben verificarse estrictamente para evitar excepciones de clúster o errores de conjunto de resultados causados por la conversión de tipos. Estos son algunos ejemplos:
- Se debería devolver timestamptz, pero se devuelve text. Los resultados parecen consistentes, pero no se pueden utilizar para la conversión de zonas horarias o el cálculo de la hora.
- Se debería devolver timestamptz, pero se devuelve timestamp. Como resultado, se pierde la información de la zona horaria, lo que provoca una desviación en el cálculo de la hora.
- La conversión forzosa de tipos incompatibles provoca errores en las invocaciones de la función C.
- Durante la invocación de una función C de memoria, se requiere un parámetro timestamptz, pero se pasa un parámetro timestamp. Esto genera un error en la conversión de la zona horaria.
- Recarga de funciones
Para los tipos que admiten la conversión implícita automática (como de text o timestamp a timestamptz), defina una función unificada para evitar la implementación redundante.
- Desarrollo de funciones
Se recomienda utilizar funciones nativas de DWS para definir nuevas funciones. Esto se debe a que los conjuntos de resultados de las nuevas funciones definidas mediante funciones compatibles pueden ser inestables debido a problemas de compatibilidad, como actualizaciones de versiones.
- Cambio de función
La cantidad y los tipos de parámetros de la función, una vez definidos, no se pueden cambiar. Esto evita errores en la lógica del servicio del usuario.
También se prohíben los cambios incompatibles en el comportamiento de la función. Si tales cambios son necesarios, deben ser controlados por los parámetros GUC de la base de datos para evitar conflictos con las dependencias de la base de datos.
Ejemplo de desarrollo de funciones
Las nuevas funciones deben agregarse al archivo de dialecto correspondiente al directorio dialects y procesarse en el script de actualización.
- Función SQL
1 2 3
CREATE FUNCTION func_add_sql(integer, integer) RETURNS integer AS 'select $1 + $2;' LANGUAGE SQL IMMUTABLE;
- Función PL/SQL. El desarrollo de funciones PL/pgSQL debe cumplir con el uso de PL/pgSQL.
1 2 3 4 5 6
CREATE OR REPLACE FUNCTION func_increment_plsql(i integer) RETURNS integer AS $$ BEGIN RETURN i + 1; END; $$ LANGUAGE plpgsql;
- Función C
Se pueden agregar funciones C independientes (algunas funciones básicas de DWS) al complemento. Compile funciones en el archivo .cpp existente o nuevo del complemento:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
PG_FUNCTION_INFO_V1(rand_seed); extern "C" Datum rand_seed(PG_FUNCTION_ARGS); Datum rand_seed(PG_FUNCTION_ARGS) { int128 n = PG_ARGISNULL(0) ? 0 : PG_GETARG_INT64(0); int elevel = ERROR; if (unlikely(n > PG_UINT64_MAX)) { elog(elevel, "Truncated incorrect DECIMAL value"); n = PG_UINT64_MAX; } else if (unlikely(n < PG_INT64_MIN)) { elog(elevel, "Truncated incorrect DECIMAL value"); n = PG_INT64_MIN; } gs_srandom((unsigned int)n); float8 result; /* result [0.0 - 1.0) */ result = (double)gs_random() / ((double)MAX_RANDOM_VALUE + 1); PG_RETURN_FLOAT8(result); }
Registre la función C en el archivo SQL del complemento.
1 2 3 4 5 6
CREATE OR REPLACE FUNCTION __dialect_mysql__.rand_seed(int) returns double precision LANGUAGE C volatile NOT FENCED as '$libdir/libsql_dialect', 'rand_seed';