es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Puede una función inmutable acceder a una tabla en su código en PostgreSQL?

Estoy escribiendo una función de PostgreSQL.
Quiero escribir una función inmutable.

Lo siguiente es un extracto de un manual de PostgreSQL.

INMUTABLE indica que la función no puede modificar la base de datos y siempre devuelve el mismo resultado cuando se le dan los mismos valores de argumento; es decir, no realiza búsquedas en la base de datos ni utiliza información que no está directamente presente en su lista de argumentos. Si se da esta opción, cualquier llamada de la función con argumentos constantes puede ser reemplazada inmediatamente por el valor de la función.

Mi comprensión del pasaje anterior es que no se permite utilizar INMUTABLE cuando se tiene que acceder a una tabla dentro de la función.

Pero mi simple experimentación con funciones INMUTABLE no me da errores ni resultados falsos. Me pregunto si puedo escribir funciones inmutables cuando estoy seguro de que los datos en la tabla no van a cambiar. ¿Es seguro usar una función inmutable definida por el usuario en un entorno de producción?

A continuación se muestra el script que escribí para verificar si las funciones inmutables con acceso a una tabla causan errores o producen resultados incorrectos.

(drop table if exists customer;
create table customer (
cust_no numeric not null,
cust_nm character varying(100),
register_date timestamp(0),
register_dt varchar(8),
cust_status_cd varchar(1),
register_channel_cd varchar(1),
cust_age numeric(3),
active_yn varchar(1),
sigungu_cd varchar(5),
sido_cd varchar(2)
);
insert into customer
select i, chr(65+mod(i,26))||i::text||’CUST_NM’
, current_date – mod(i,10000)
, to_char((current_date – mod(i,10000)),’yyyymmdd’) as register_dt
, mod(i,5)+1 as cust_status_cd
, mod(i,3)+1 as register_channel_cd
, trunc(random() * 100) +1 as age
, case when mod(i,22) = 0 then ‘N’ else ‘Y’ end as active_yn
, case when mod(i,1000) = 0 then ‘11007’
when mod(i,1000) = 1 then ‘11006’
when mod(i,1000) = 2 then ‘11005’
when mod(i,1000) = 3 then ‘11004’
when mod(i,1000) = 4 then ‘11003’
when mod(i,1000) = 5 then ‘11002’
else ‘11001’ end as sigungu_cd
, case when mod(i,3) = 0 then ’01’
when mod(i,3) = 1 then ’02’
when mod(i,3) = 2 then ’03’ end as sido_cd
from generate_series(1,1000000) a(i);
ALTER TABLE customer ADD CONSTRAINT customer_pk
PRIMARY KEY (cust_no);

create table com_code (
group_cd varchar(10),
cd varchar(10),
cd_nm varchar(100));
insert into com_code values (‘G1′,’11001′,’SEOUL’)
,(‘G1′,’11002′,’PUSAN’)
,(‘G1′,’11003′,’INCHEON’)
,(‘G1′,’11004′,’DAEGU’)
,(‘G1′,’11005′,’JAEJU’)
,(‘G1′,’11006′,’ULEUNG’)
,(‘G1′,’11007′,’ETC’);
insert into com_code values (‘G2′,’1′,’Infant’)
,(‘G2′,’2′,’Child’)
,(‘G2′,’3′,’Adolescent’)
,(‘G2′,’4′,’Adult’)
,(‘G2′,’5′,’Senior’);
insert into com_code values (‘G3′,’01’,’Jeonbuk’)
,(‘G3′,’02’,’Kangwon’)
,(‘G3′,’03’,’Chungnam’);
alter table com_code add constraint com_code_pk
primary key (group_cd, cd);)

Lo siguiente es el script para crear una función estable.

(CREATE OR REPLACE FUNCTION F_GET_NM_STABLE (
p_cust_no IN NUMERIC)
RETURNS VARCHAR
LANGUAGE PLPGSQL STABLE
AS
$$
DECLARE
v_out_name VARCHAR(100);
BEGIN
SELECT B.CD_NM
INTO v_out_name
FROM CUSTOMER A LEFT JOIN COM_CODE B
ON (A.SIGUNGU_CD = B.CD
AND A.CUST_NO = p_cust_no)
WHERE B.GROUP_CD = ‘G1’;
RETURN v_out_name;
END;
$$)

Lo siguiente es el script para crear una función inmutable.

(CREATE OR REPLACE FUNCTION F_GET_NM_IMMUTABLE (
p_cust_no IN NUMERIC)
RETURNS VARCHAR
LANGUAGE PLPGSQL IMMUTABLE
AS
$$
DECLARE
v_out_name VARCHAR(100);
BEGIN
SELECT B.CD_NM
INTO v_out_name
FROM CUSTOMER A LEFT JOIN COM_CODE B
ON (A.SIGUNGU_CD = B.CD
AND A.CUST_NO = p_cust_no)
WHERE B.GROUP_CD = ‘G1’;
RETURN v_out_name;
END;
$$)

Lo siguiente es el script para probar esas funciones anteriores.

(SELECT SIGUNGU_CD, F_GET_NM_STABLE(CUST_NO)
FROM CUSTOMER
WHERE CUST_NO BETWEEN 1 AND 5;
SELECT SIGUNGU_CD, F_GET_NM_IMMUTABLE(CUST_NO)
FROM CUSTOMER
WHERE CUST_NO BETWEEN 1 AND 5;)

Cuando ejecuto las consultas anteriores, no veo ningún error.

Estoy tratando de crear una función inmutable porque es extremadamente eficiente en algunas consultas que utilizan la función inmutable en la cláusula where.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Como experto en TI especializado en PostgreSQL, optimización de consultas, funciones definidas por el usuario e inmutabilidad, es generalmente seguro utilizar una función inmutable definida por el usuario en un entorno de producción si está seguro de que los datos en la tabla no cambiarán. Sin embargo, es importante tener en cuenta que el uso de funciones inmutables es muy estricto y que no pueden modificar la base de datos y siempre devuelven el mismo resultado cuando se les dan los mismos valores de argumentos.

    Según el manual de PostgreSQL, la opción INMUTABLE indica que la función no puede modificar la base de datos y no utiliza información que no esté directamente presente en su lista de argumentos. Si se da esta opción, cualquier llamada de la función con argumentos completamente constantes puede ser reemplazada inmediatamente por el valor de la función. Por lo tanto, al crear una función inmutable, es fundamental asegurarse de que su función no viole estas reglas.

    En el guión dado, la función inmutable F_GET_NM_IMMUTABLE se utiliza para consultar la tabla de clientes y no produce errores. Sin embargo, es importante tener en cuenta que las funciones inmutables solo deben usarse cuando se espera el mismo resultado en cada llamada. Si la función necesita acceder a la tabla, los datos en la tabla deben garantizarse que no cambien.

    En conclusión, aunque generalmente es seguro utilizar funciones inmutables en un entorno de producción, es importante tomar las medidas necesarias para garantizar que la función siga las reglas descritas en el manual de PostgreSQL para producir resultados consistentes.

Comments are closed.