Tengo un problema con la planificación de consultas PostgreSQL 9.6. Mi consulta se ve así:
SET role plain_user;
SELECT properties.*
FROM properties
JOIN entries_properties
ON properties.id = entries_properties.property_id
JOIN structures
ON structures.id = entries_properties.entry_id
WHERE structures."STRUKTURBERICHT" != ''
AND properties."COMPOSITION" LIKE 'Mo%'
AND (
properties."NAME" LIKE '%VASP-ase-preopt%'
OR properties."CALCULATOR_ID" IN (7,22,25)
)
AND properties."TYPE_ID" IN (6)
Tengo habilitada la seguridad de nivel de fila para las tablas utilizadas anteriormente.
con
set enable_nestloop = True
, el planificador de consultas ejecuta Nested Loop uniéndose con un tiempo de ejecución total de aproximadamente 37 segundos: https://explain.depesz.com/s/59BRcon
set enable_nestloop = False
, se utiliza el método Hash Join y el tiempo de consulta es de aproximadamente 0.3 segundos: https://explain.depesz.com/s/PG8E
Lo hice VACUUM ANALYZE
antes de ejecutar las consultas, pero no ayudó.
Sé que no es una buena práctica set enable_nestloop = False
, y cualquier otra opción similar para el planificador. Pero, ¿cómo podría "convencer" al planificador de que use combinaciones hash sin deshabilitar los bucles anidados?
Reescribir la consulta es una opción.
Si ejecuto la misma consulta bajo un rol que omite RLS, entonces se ejecuta muy rápido. La política de seguridad de nivel de fila se ve así:
CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
(
properties.ouid = get_current_user_id()
AND properties.ur
)
OR (
properties.ogid in (select get_current_groups_id())
AND properties.gr
)
OR properties.ar
);
Cualquier idea o sugerencia sería muy apreciada.
fuente
AND properties."TYPE_ID" IN (6);
y no= 6;
?Respuestas:
Lo que está sucediendo aquí es que el Nested Loop está muy alejado de un lado. Los bucles anidados funcionan realmente bien cuando un lado es muy pequeño, como devolver una fila. En su consulta, el planificador se equivoca aquí y estima que una Hash Join devolverá solo una fila. En cambio, esa Hash Join (property_id = id) devuelve 1,338 filas. Esto obliga a 1,338 bucles a correr en el otro lado del bucle anidado que ya tiene 3,444 filas. Eso es un montón cuando solo esperas uno (que ni siquiera es un "bucle"). De todos modos ..
Un examen más detallado a medida que avanzamos muestra que Hash Join está realmente alterado por las estimaciones derivadas de esto,
PostgreSQL espera que eso devuelva una fila. Pero no lo hace. Y ese es realmente tu problema. Entonces, algunas opciones aquí, que no implican sacar un martillo y deshabilitar
nested_loop
Puede agregar un índice o dos para
properties
ayudarlo a omitir por completo el análisis de secuencia, o estimar mejor el rendimiento.Alternativamente, puede mover las cosas de propiedades a un CTE o subseleccionar con las
OFFSET 0
cuales crea una cerca.fuente