On 08/08/12 18:47, Jaime Casanova wrote:
2012/8/8 Igor <igor@negora.com>:
Analizando el plan de la consulta (anteponiendo "analyze" a ésta) aparece
esto:

Hash Join  (cost=15.34..31.26 rows=166 width=8)
  Hash Cond: (s.father_id = f.father_id)
  ->  Seq Scan on sons s  (cost=0.00..13.10 rows=310 width=8)
  ->  Hash  (cost=14.00..14.00 rows=107 width=4)
        ->  Seq Scan on fathers f  (cost=0.00..14.00 rows=107 width=4)
              Filter: (father_id < 10)

Supongo que se me está escapando algo importante pero, ¿Por que en esa línea
marcada en negrita (la búsqueda secuencial en "sons") el planificador no
restringe la búsqueda también a aquellos hijos con código de padre menor a
10, como hace al buscar los padres? ¿Significa este plan que pese a obtener
10 padres, luego recorre absolutamente todos los hijos y no sólo los que
tienen código de padre menor que 10 (pese a que hay un índice "btree" creado
en la columna "father_id" de la tabla "sons")?

He probado a llenar las tablas con 10 millones de registros y, tras ejecutar
"analyze", el resultado es el mismo.

Que version de postgres esta? con solo 310 registros creo que es
normal que haga un seq scan pero con 10 millones deberia usar un
indice.

a mi me funciona asi (de hecho solo inserte 10000 en fathers y 30000
en sons) aun asi usa indices en ambas tablas (no necesita el filtro en
sons porque al usar el indice y chequear solo los resultados que
obtuvo de fathers el filtro esta implicito)

pero si, cuando hace un seq scan no hereda filtros aun cuando haya un
FK que relacione los dos campos.
ai quieres ver el filtro agregua una condicion "s.fathers_id < 10"
adicional si quieres que use ese filtro

pero, un seq scan igual leera toda la tabla (filtro o no filtro)


Hola Jaime:

Ante todo, gracias por tu respuesta. La versión que uso de PostgreSQL es la 9.0.1, en un Linux de 64-bit (Kubuntu).

Hoy he vuelto a probar añadiendo 10.000 y 30.000 registros, como en tu caso, y el resultado es el que sigue:

Así que supongo que ayer, por trastear demasiado, los índices pudieron haberse corrompido y por eso jamás eran usados. En un momento me quedé incluso sin espacio en disco, así que es altamente probable que esto tuviera que ver. Los 20.000.000 de registros que introduje tienen la culpa muy probablemente, je je je.

Volviendo a la pregunta original, y pensando en esos 3 casos que he testado, veo muy lógicos el primero (10) y el tercero (6000). El primero, porque son poquísimos registros. Y el tercero, porque al devolver tantos, es más rápido recorrer ambas tablas que usar índices.

El que me costaba entender es el segundo (100). Y creo que se debe a que el resultado de "explain" es un poco ambiguo. Da a entender (al menos a mí) que en el "hash join" por un lado se obtiene el "hash" de 100 filas de "fathers", por otro se obtienen las 30.000 filas de "sons" al completo (el planificador no aplica índice ni filtro en este caso) y que luego se hace el producto cartesiano de eso. Entiendo que la manera correcta de interpretarlo es que el producto se hace mientras se recorren las 30.000 y no después de ello, como es lógico. ¿Es así, verdad?

Aparte de eso, también me costaba entender como para 300 registros (100 * 3; muy pocos) esa técnica era más rápida que usar un "nested loop". Pero pensando en cómo funciona un índice de tipo "btree" y la cantidad de búsquedas a realizar, la verdad es que me he dado cuenta de que sí, que un barrido en secuencia puede ser mucho más rápido en ese caso. Es más, yo mismo uso esa misma técnica cuando programo en Java productos cartesianos y ni siquiera me había dado cuenta de que es un caso semejante.

Un saludo y gracias.