2012-02-14 13 views
6

En PostgreSQL, ¿cuándo se planifican las consultas (SELECT)?¿Cuándo se planifican las consultas (SELECT)?

se encuentra:

  1. en tiempo de declaración de preparar o
  2. en el inicio de la tramitación de la SELECT o
  3. algo más

La razón que pido es que hay es una pregunta de Stackoverflow: same query, two different ways, vastly different performance

Mucha gente parece pensar que t La consulta se planifica de manera diferente porque en un caso la consulta contiene un literal de cadena ('foo') y en otro caso es un marcador de posición (?).

Ahora mi pensamiento es que esto es una pista falsa, porque la consulta no está planificada en el momento de preparación de la declaración, pero en realidad está planificada en la hora SELECCIONAR.

Así que, por ejemplo, podría preparar una declaración con un marcador de posición, luego ejecutar la consulta varias veces con diferentes valores encuadernados, y el planificador de consultas se ejecutará para cada valor encuadernado diferente.

sospecho que el question linked above se reduce al tipo de datos PostgreSQL del valor, que en el caso de un 'foo' literal se sabe que es una cadena, pero en el caso de un marcador de posición, el tipo no se evidencian , por lo tanto, llega al planificador de consultas como un tipo extraño, para el cual no puede crear un plan eficiente. En ese caso, el problema no es que la consulta se planifique de manera diferente porque el valor es un marcador de posición (en el momento de preparación de la instrucción) per se sino que el valor está llegando a la consulta como un tipo diferente de PostgreSQL y que es lo que influye en el planificador de consultas. Solucionar esto simplemente sería una cuestión de vincular el marcador de posición con una declaración de tipo explícita apropiada.

+1

¡Buena pregunta! Esto es muy específico de DBMS; diferentes DBMS presentan respuestas (ligeramente) diferentes. El resultado neto puede ser dramáticamente diferente. Informix admite un 'CIERRE ABIERTO UTILIZANDO ... CON REOPTIMIZACIÓN' que no tiene que volver a analizar el SQL (lo que ahorra tiempo) pero rehace el plan de consulta para el conjunto actual de parámetros. Eso es diferente nuevamente de la mayoría de DBMS. –

+0

Sí. Esta pregunta está demostrando ser sorprendentemente controvertida.Tenemos upvotes y downvote sobre la pregunta y una de las respuestas. – zgpmax

+0

@hochgurgler: Su sospecha sobre el tipo de desajuste es en sí misma una preocupación válida, PostgreSQL _tiene_ algunos problemas conocidos aquí. Pero considerando la primera parte de la pregunta, creo que estas dos cuestiones no deben mezclarse y que la segunda parte se manejará mejor con una pregunta separada. ¿Podrías por favor dividirlo? –

Respuesta

10

No puedo hablar sobre la interfaz Perl del lado del cliente en sí, pero puedo arrojar algo de luz sobre el lado del servidor PostgreSQL.

PostgreSQL tiene declaraciones preparadas y declaraciones no preparadas. Las declaraciones no preparadas se analizan, planifican y ejecutan de inmediato. También hacen no sustitución de parámetros de soporte. En un psql cáscara normal puede mostrar su plan de consulta como esta:

tmpdb> explain select * from sometable where flag = true; 

Por otro lado, hay declaraciones preparadas: Por lo general son (ver "excepción" a continuación) analiza y se planeó en un solo paso y ejecutado segundo paso. Se pueden volver a ejecutar varias veces con diferentes parámetros, ya que hacen sustitución de parámetros de soporte.El equivalente en psql es la siguiente:

tmpdb> prepare foo as select * from sometable where flag = $1; 
tmpdb> explain execute foo(true); 

Usted puede ver, que el plan es diferente del plan en el estado preparado, porque la planificación tuvo lugar ya en la fase prepare como se describe en el documento de PREPARE:

Cuando se ejecuta la sentencia PREPARE, la instrucción especificada es Analizada, reescrito, y planificada. Cuando se emite un comando EXECUTE posteriormente, la declaración preparada solo debe ejecutarse. Por lo tanto, las etapas de análisis, reescritura y planificación solo se realizan una vez, en lugar de cada vez que se ejecuta la instrucción.

Esto significa también, que el plan es NO optimizado para los parámetros sustituidos: En los primeros ejemplos podría utilizar un índice para flag porque PostgreSQL sabe que dentro de un millón de entradas sólo diez han el valor true. Este razonamiento es imposible cuando PostgreSQL usa una declaración preparada. En ese caso, se crea un plan que funcionará para todos los posibles valores de parámetros lo mejor posible. Este podría excluir el índice mencionado porque recuperar la mejor parte de la tabla completa a través de acceso aleatorio (debido al índice) es más lento que un escaneo secuencial simple. El documento PREPARE confirma:

En algunas situaciones, el plan de consulta producido por una declaración preparada será inferior a la del plan de consulta que se habrían elegido si la declaración había sido presentado y ejecutado normalmente. Esto se debe a que cuando se planifica la declaración y el planificador intenta determinar el plan de consulta óptimo, los valores reales de los parámetros especificados en la declaración no están disponibles. PostgreSQL recopila estadísticas sobre la distribución de datos en la tabla, y puede usar valores constantes en una declaración para hacer suposiciones sobre el resultado probable de ejecutar la instrucción. Dado que estos datos no están disponibles cuando se planifican las declaraciones preparadas con parámetros, el plan elegido puede ser subóptimo.

BTW - En cuanto a plan de almacenamiento en caché el doc PREPARE también tiene algo que decir:

Declaraciones preparadas sólo duran durante la duración de la sesión de base de datos actual. Cuando la sesión finaliza, la declaración preparada se olvida, por lo que debe recrearse antes de volver a utilizarse.

Además, no hay un almacenamiento en caché automático y no hay almacenamiento en caché/reutilización en varias conexiones.

EXCEPCIÓN: He mencionado "generalmente". Los ejemplos mostrados de psql no son lo que realmente usa un adaptador de cliente como Perl DBI. Utiliza un cierto protocol. Aquí el término "consulta simple" corresponde a la "consulta no preparada" en psql, el término "extended query" corresponde a "consulta preparada" con una excepción: hay una distinción entre (una) "declaración sin nombre" y (posiblemente múltiple) " declaraciones nombradas ". Con respecto a las declaraciones con nombre, doc dice:

Las declaraciones preparadas con nombre también se pueden crear y acceder al nivel de comando de SQL, usando PREPARE y EXECUTE.

y también: la planificación

de consulta para los objetos-declaración preparada nombradas se produce cuando se procesa el mensaje de analizar.

En este caso, la planificación se realiza sin los parámetros descritos anteriormente para PREPARE - nada nuevo.

La excepción mencionada es la "declaración sin nombre". El doctor dice:

la declaración preparada sin nombre está asimismo previsto durante el procesamiento Analizar si el mensaje Analizar define ningún parámetro. Pero si hay parámetros, la planificación de consultas se produce cada vez que se suministran parámetros de vinculación. Esto permite al planificador utilizar los valores reales de los parámetros proporcionados por cada mensaje de vinculación, en lugar de utilizar estimaciones genéricas.

Y aquí está el beneficio: Aunque la declaración sin nombre está "preparada" (es decir, puede tener sustitución de parámetros), también puede adaptar el plan de consulta a los parámetros reales.

BTW: El manejo exacto de la instrucción sin nombre ha cambiado varias veces en las versiones anteriores del servidor PostgreSQL. Puede buscar los documentos antiguos para obtener detalles si realmente lo desea.

Justificación - Perl/cualquier cliente:

cómo un cliente como Perl utiliza el protocolo es una cuestión completamente diferente. Algunos clientes como el controlador JDBC para Java dicen básicamente: incluso si el programador usa una declaración preparada, las primeras cinco (más o menos) ejecuciones se mapean internamente a una "consulta simple" (es decir, sin preparación efectiva), luego el controlador cambia a " declaración nombrada ".

Así que un cliente tiene estas opciones:

  • Fuerza (re) la planificación de cada momento utilizando el protocolo de "consulta sencilla".
  • Plan una vez, ejecútelo varias veces utilizando el protocolo de "consulta extendida" y la "declaración con nombre" (el plan puede estar mal porque la planificación se realiza sin parámetros).
  • Analizar vez, el plan para cada ejecución (con la versión actual de PostgreSQL) utilizando el protocolo "consulta extendida" y la "declaración sin nombre" y obedecer algunas cosas más (proporcionar algunos parametros durante el mensaje de "analizar")
  • Juega trucos completamente diferentes como el controlador JDBC.

Lo que Perl hace actualmente: No lo sé. Pero el mencionado "arenque rojo" no es muy improbable.

+0

+1 pero vale más! –

+0

+1 Muy informativo. –

+0

Semi-Actualización: Desde la versión 9.2, la planificación es un poco diferente. Básicamente, incluso las consultas preparadas se planificarán para cada invocación utilizando los parámetros reales. Solo después de que se hayan comprobado varias invocaciones, de que los planes no difieren demasiado, se utiliza un plan genérico. –

Cuestiones relacionadas