Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   A vueltas con un query (https://www.clubdelphi.com/foros/showthread.php?t=96477)

Angel.Matilla 07-11-2023 13:40:08

A vueltas con un query
 
Y va el tercer hilo (Filtrar resultados en un query y ¿Y por qué no funciona el ORDER BY?) con el mismo problema. He encontrado otra manera de sacar los resultados y esta vez funciona:
Código SQL [-]
SELECT A.Codigo, A.Nombre, COALESCE(SUM(B.Votos), 0) Votos, COALESCE(C.Electos, 0) Electos, C.Circunscripcion, D.Nombre
  FROM Partidos A, Resultados B
  LEFT JOIN NumElectos C ON B.CodPrv = C.CodPrv AND B.Proceso = C.Proceso AND C.Tipo = 'M' AND B.Partido = C.Partido,
  Poblacion D
 WHERE A.CodPrv = :PrvIns 
   AND B.Proceso = :Proceso AND A.CodPrv = B.CodPrv AND B.Partido = A.Codigo
   AND B.Mesa IN (SELECT Codigo FROM Mesas WHERE CodPrv = A.CodPrv AND Municipio = C.Circunscripcion)
   AND A.CodPrv = D.CodPrv AND C.Circunscripcion = D.Codigo
 GROUP BY A.Codigo, A.Nombre, Electos, C.Circunscripcion, D.Nombre
 ORDER BY D.Nombre, Votos DESC, Electos DESC, A.Nombre
Las tablas implicadas en el query son estas:
Código SQL [-]
CREATE TABLE PARTIDOS (
  CODPRV VARCHAR(3) CHARACTER SET ISO8859_1 DEFAULT '13' NOT NULL COLLATE ES_ES_CI_AI,
  CODIGO SMALLINT NOT NULL,
  NOMBRE VARCHAR(45) CHARACTER SET ISO8859_1 NOT NULL COLLATE ES_ES_CI_AI,
  SIGLA VARCHAR(10) CHARACTER SET ISO8859_1 COLLATE ES_ES_CI_AI,
  ACTIVO SMALLINT DEFAULT 1,
  COLOR INTEGER DEFAULT 0);

ALTER TABLE PARTIDOS ADD CONSTRAINT PK_PARTIDOS PRIMARY KEY (CODPRV,CODIGO);

Código SQL [-]
CREATE TABLE RESULTADOS (
  CODPRV VARCHAR(3) CHARACTER SET ISO8859_1 DEFAULT '13' NOT NULL COLLATE ES_ES_CI_AI,
  PROCESO INTEGER NOT NULL,
  MESA INTEGER NOT NULL,
  PARTIDO INTEGER DEFAULT 1 NOT NULL,
  VOTOS INTEGER);

ALTER TABLE RESULTADOS ADD CONSTRAINT PK_RESULTADOS PRIMARY KEY (CODPRV,PROCESO,MESA,PARTIDO);

Código SQL [-]
CREATE TABLE NUMELECTOS (
  CODPRV VARCHAR(3) CHARACTER SET ISO8859_1 DEFAULT '13' NOT NULL COLLATE ES_ES_CI_AI,
  PROCESO INTEGER NOT NULL,
  TIPO VARCHAR(2) CHARACTER SET ISO8859_1 NOT NULL COLLATE ES_ES_CI_AI,
  CIRCUNSCRIPCION INTEGER DEFAULT 1 NOT NULL,
  PARTIDO INTEGER DEFAULT 1 NOT NULL,
  CARGO INTEGER NOT NULL,
  ELECTOS INTEGER NOT NULL);

ALTER TABLE NUMELECTOS ADD CONSTRAINT PK_NUMELECTOS PRIMARY KEY (CODPRV,PROCESO,TIPO,CIRCUNSCRIPCION,PARTIDO,CARGO);

Código SQL [-]
CREATE TABLE POBLACION (
  CODPRV VARCHAR(3) CHARACTER SET ISO8859_1 DEFAULT '13' NOT NULL COLLATE ES_ES_CI_AI,
  CODIGO INTEGER NOT NULL,
  NOMBRE VARCHAR(65) CHARACTER SET ISO8859_1 NOT NULL COLLATE ES_ES_CI_AI,
  CPOSTAL VARCHAR(10) CHARACTER SET ISO8859_1 NOT NULL COLLATE ES_ES_CI_AI,
  PAIS VARCHAR(2) CHARACTER SET ISO8859_1 DEFAULT 'ES' COLLATE ES_ES_CI_AI,
  CODINE VARCHAR(6) CHARACTER SET ISO8859_1 COLLATE ES_ES_CI_AI,
  JUDICIAL INTEGER DEFAULT 1);

ALTER TABLE POBLACION ADD CONSTRAINT PK_POBLACION PRIMARY KEY (CODPRV,CODIGO);

Código SQL [-]
CREATE TABLE MESAS (
  CODPRV VARCHAR(3) CHARACTER SET ISO8859_1 DEFAULT '13' NOT NULL COLLATE ES_ES_CI_AI,
  CODIGO INTEGER NOT NULL,
  MUNICIPIO INTEGER DEFAULT 1 NOT NULL,
  DISTRITO SMALLINT NOT NULL,
  SECCION SMALLINT NOT NULL,
  MESA VARCHAR(2) CHARACTER SET ISO8859_1 DEFAULT 'U' NOT NULL COLLATE ES_ES_CI_AI);
Puede darse la circunstancia de que no se hayan grabado o calculado todavía los electos (tabla NumElectos) para una determinado proceso y/o circunscripción. He hecho la prueba borrando todas las entradas de esa tabla para un determinado proceso y al ejecutar el query no me devuelve ninguna fila aunque el resto de tablas implicadas sí tengan información.

Yo tenía la idea que con el LEFT JOIN se obtenía resultados aunque en esa tabla no hubiera información que se ajustara a las condiciones. Si estoy equivocado os rogaría que me iluminaráis. Gracias.

duilioisola 07-11-2023 14:01:42

En este caso debes agregar la condición a la parte de la UNION entre tablas (ON ...)
De esta forma hace el JOIN y como es de tipo LEFT no importa que no tenga datos...

Algo así... pero tendrías que utilizar un LEFT JOIN para RESULTADOS porque filtras por mesas que estén en la circunscripcion.
Código SQL [-]
select a.codigo, a.nombre, coalesce(sum(b.votos), 0) votos, coalesce(c.electos, 0) electos, c.circunscripcion,
       d.nombre
from partidos a, resultados b, poblacion d
left join numelectos c on b.codprv = c.codprv and b.proceso = c.proceso and c.tipo = 'M' and b.partido = c.partido and d.codigo = c.circunscripcion /* paso aqui la condicion */
where
a.codprv = : prvins and
b.proceso = : proceso and
a.codprv = b.codprv and
b.partido = a.codigo and
b.mesa in (select codigo
           from mesas
           where
           codprv = a.codprv and
           municipio = c.circunscripcion) and
a.codprv = d.codprv
/* and c.circunscripcion = d.codigo */
group by a.codigo, a.nombre, electos, c.circunscripcion, d.nombre
order by d.nombre, votos desc, electos desc, a.nombre

Yo te recomentadría utilizar JOIN / LEFT JOIN para unir las 4 tablas y no mezclar diferentes formas de hacerlo.

duilioisola 07-11-2023 14:07:36

Transformado a JOINS
Código SQL [-]
select a.codigo, a.nombre, coalesce(sum(b.votos), 0) votos, coalesce(c.electos, 0) electos, c.circunscripcion,
       d.nombre
from partidos a
join resultados b on b.partido = a.codigo and a.codprv = b.codprv
join poblacion d on a.codprv = d.codprv
left join numelectos c on b.codprv = c.codprv and b.proceso = c.proceso and c.tipo = 'M' and b.partido = c.partido and d.codigo = c.circunscripcion
where
a.codprv = : prvins and
b.proceso = : proceso and
/* Que pasa si no hay ninguna mesa con esa circunscripcion */
b.mesa in (select codigo
           from mesas
           where
           codprv = a.codprv and
           municipio = c.circunscripcion)
group by a.codigo, a.nombre, electos, c.circunscripcion, d.nombre
order by d.nombre, votos desc, electos desc, a.nombre

Angel.Matilla 07-11-2023 20:03:15

Cita:

Empezado por duilioisola (Mensaje 553180)
Transformado a JOINS

Gracias por la sugerencia. Tengo que estudiarla porque tal cual me la has planteado he tendio que abortar la ejecución porque llevaba 10 minutos sin sacar nada y tal como he planteado el query yo se ejecutaba en menos de 1 segundo.

Angel.Matilla 07-11-2023 20:40:13

Cita:

Empezado por duilioisola (Mensaje 553180)
Transformado a JOINS

Gracias por la idea. He estado probando y si ejecuto el query tal como me propones, como te he dicho antes, se eterniza y tengo que cancelar la ejecución porque llevando 10 minutos no ha sacado nada, y es lógico porque, a mi modesto entender, trataría de sacar todas las filas de la tabla poblacion; y si hago un pequeño cambio:
Código SQL [-]
from partidos a
join resultados b on b.partido = a.codigo and a.codprv = b.codprv
left join numelectos c on b.codprv = c.codprv and b.proceso = c.proceso and c.tipo = 'M' and b.partido = c.partido
join poblacion d on a.codprv = d.codprv and d.codigo = c.circunscripcion
Si no hay datos en NumElectos no saca nada. Seguiré investigando, pero ya mañana.

duilioisola 08-11-2023 09:50:48

Si haces LEFT JOIN con numelectos, también debes hacer LEFT JOIN con las tablas que se unen a ella.
Si numelectos no tiene registros, C.CIRCUNSCRIPCION será nulo y el JOIN con población no devolverá nada.

Código SQL [-]
from partidos a
join resultados b on b.partido = a.codigo and a.codprv = b.codprv
left join numelectos c on b.codprv = c.codprv and b.proceso = c.proceso and c.tipo = 'M' and b.partido = c.partido
*LEFT* join poblacion d on a.codprv = d.codprv and d.codigo = c.circunscripcion

Código SQL [-]
from partidos a
join resultados b on b.partido = a.codigo and a.codprv = b.codprv
left join numelectos c on b.codprv = c.codprv and b.proceso = c.proceso and c.tipo = 'M' and b.partido = c.partido
*LEFT* join poblacion d on a.codprv = d.codprv and d.codigo = c.circunscripcion
*LEFT JOIN* mesas on  codprv = a.codprv and municipio = c.circunscripcion

Para que no se haga eterno deberás tener índices para los campos con los que haces el JOIN.
He visto que tienes PKs, que generan índices para estas tablas, pero que quizás no sean óptimos.

Por ejemplo

Quizás NUMELECTOS debería cambiar el orden de los campos de la PK a CODPRV,PROCESO,TIPO,[PARTIDO <- , -> CIRCUNSCRIPCION],CARGO para que se utilice mejor en el LEFT JOIN.
POBLACION debería tener un índice por CODPRV,CODIGO.
MESAS no tiene ningún índice.

Angel.Matilla 08-11-2023 11:09:05

Gracias por la orientación.

Angel.Matilla 08-11-2023 11:34:29

Cita:

Empezado por duilioisola (Mensaje 553192)
Quizás NUMELECTOS debería cambiar el orden de los campos de la PK a CODPRV,PROCESO,TIPO,[PARTIDO <- , -> CIRCUNSCRIPCION],CARGO para que se utilice mejor en el LEFT JOIN.
POBLACION debería tener un índice por CODPRV,CODIGO.
MESAS no tiene ningún índice.

Perdona por no haber puesto todo.
POBLACION tiene como clave primaria precisamente esa.
MESAS tiene como clave primaria CODPRV, CODIGO. Además tiene otro índice con CODPRV y MUNICIPIO.

Angel.Matilla 08-11-2023 11:41:57

Cita:

Empezado por duilioisola (Mensaje 553192)
Si haces LEFT JOIN con numelectos, también debes hacer LEFT JOIN con las tablas que se unen a ella.
Si numelectos no tiene registros, C.CIRCUNSCRIPCION será nulo y el JOIN con población no devolverá nada.

Ahora sí. Muchísimas gracias. v:-)v v:-)v v:-)v

Angel.Matilla 13-11-2023 11:58:25

Pues no sé lo que pasa. El query funciona pero...
Si ejecuto el query como me ha propuesto duilioisola me da este resultado:

No veo de donde sale esa suma de votos que, por otra parte, es el único campo que se calcula mal. Por citar sólo un ejemplo el municipio de Alcázar de San Juan tiene un censo electoral de 23670 personas y los votos emitidos fueron 16192. Sin embargo la suma de votos que hace el query es la que se ve ahí.

Sin embargo si ejectuto este query sólo para ese municipio:
Código SQL [-]
select a.codigo, a.nombre, coalesce(sum(b.votos), 0) votos
from partidos a
join resultados b on b.partido = a.codigo and a.codprv = b.codprv
where
a.codprv = :prvins and a.codigo > 0 and
b.proceso = :proceso and
b.mesa in (select codigo
           from mesas
           where
           codprv = a.codprv and
           municipio = :municipio)
group by a.codigo, a.nombre
order by votos desc, a.nombre
El resultado es este, que es el correcto

No veo por qué se multiplican los datos. He comprobado que si divido las resultados de ambos querys de los partidos que tiene electos en todos los casos sale la misma cifra: 44

Angel.Matilla 13-11-2023 12:38:10

He estado probando añadiendo y quitando trozos del query original y descubierto que el problema viene con el último LEFT JOIN:
Código SQL [-]
LEFT JOIN mesas e on  e.codprv = a.codprv and e.municipio = c.circunscripcion
Si se deja, salen mal los datos.

Angel.Matilla 13-11-2023 14:10:48

Cada vez estoy más desanimado con este query, y mira que pintaba bien.
Código SQL [-]
select a.codigo, a.nombre, coalesce(sum(b.votos), 0) votos, coalesce(c.electos, 0) electos, c.circunscripcion, d.nombre
from partidos a
left join resultados b on b.partido = a.codigo and a.codprv = b.codprv
left join numelectos c on b.codprv = c.codprv and b.proceso = c.proceso and c.tipo = 'M' and b.partido = c.partido
LEFT join poblacion d on a.codprv = d.codprv and d.codigo = c.circunscripcion
where
a.codprv = :prvins and
b.proceso = :proceso and
b.mesa in (select codigo
           from mesas
           where
           codprv = a.codprv and
           municipio = c.circunscripcion)
group by a.codigo, a.nombre, electos, c.circunscripcion, d.nombre
order by d.nombre, votos desc, electos desc, a.nombre
He hecho la prueba con left join resultados y con join resultados y eliminando resultados en la tabla NumElectos para que de un municipio no hubiera esos campos pero sí resultados. Y con las tablas completas sale este resultado:

pero si suprimo lo que he comentado sale esto

aunque en la tabla resultados siga habiendo datos del municipio en cuestión (en este caso el 175). No lo entiendo: con LEFT JOIN ¿no deberían salir datos para ese valor? No sé que estoy haciendo mal o no entendiendo.

En el enlcae https://drive.google.com/file/d/1F3V...ew?usp=sharing hay un fichero TABLAS.RAR que tiene el script para crear y llenar las tablas implicadas en el query.

duilioisola 13-11-2023 19:11:06

Al descargar el fichero te he pedido acceso.
En cuanto pueda descargarlo haré algunas pruebas para ver qué contienen las tablas...

duilioisola 13-11-2023 22:45:27

He estado mirando las tablas...

Primera parte
La primera duda es cómo se unen mesa, poblacion y numelectos.
He inferido que mesas.codigo, poblacion.municipio y numelectos.circunscripcion es el mismo campo y lo he utilizado para los joins.

La segunda duda es qué es proceso? He inferido que se trata de diferentes votaciones y he estado utilizando la número 42.

Segunda parte.
Lo primero que necesitas antes de hacer las acumulaciones es la tabla con todos los datos necesarios unidos mediante JOIN / LEFT JOIN.
  • Parto de PARTIDOS y le uno los RESULTADOS.
  • Los RESULTADOS son de MESAS. Por lo tanto se unen a RESULTADOS.
  • Las MESAS pertenecen a POBLACIONES, que se unen por el campo MUNICIPIO.
  • Finalmente, NUMELECTOS se une mediante LEFT JOIN porque no necesariamente tiene electos para cada PROCESO-PROVINCIA-PARTIDO-MUNICIPIO
Esto me deja el siguiente SQL con alias identificados con la primera letra del nomrbre de la tabla. (excepto POBLACION po).
Este SQL devuelve 113511 registros.
Todos con valores excepto los que pertenecen a la tabla NUMELECTOS que a veces son nulos.
Código SQL [-]
select *
from partidos p
join resultados r on r.partido = p.codigo and p.codprv = r.codprv
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo
left join numelectos n on r.codprv = n.codprv and r.proceso = n.proceso and n.tipo = 'M' and r.partido = n.partido and po.codigo = n.circunscripcion

Ahora agrego el where para limitar los datos a tratar.
En este caso he elegido alguno que devuelve datos y que hemos hablado en este hilo
Este SQL devuelve 8 registros.
Todos con valores excepto los que pertenecen a la tabla NUMELECTOS que a veces son nulos.
Código SQL [-]
where
p.codprv = 13 and
r.proceso = 42 and
m.municipio = 175

Final
Ya tenemos los datos. Ahora solo tenemos que agruparlos y ordenarlos.

Código SQL [-]
select p.codigo, p.nombre, coalesce(sum(r.votos), 0) votos, coalesce(n.electos, 0) electos, n.circunscripcion,
       po.nombre
from partidos p
join resultados r on r.partido = p.codigo and p.codprv = r.codprv
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo
left join numelectos n on r.codprv = n.codprv and r.proceso = n.proceso and n.tipo = 'M' and r.partido = n.partido and po.codigo = n.circunscripcion
where
p.codprv = 13 and
r.proceso = 42 and
m.municipio = 175
group by p.codigo, p.nombre, electos, n.circunscripcion, po.nombre
order by po.nombre, 3 /*votos*/ desc, 4 /*electos*/ desc, p.nombre

Dos formas de evitar que salgan registros "sin electos".
Código SQL [-]
select p.codigo, p.nombre, coalesce(sum(r.votos), 0) votos, coalesce(n.electos, 0) electos, n.circunscripcion,
       po.nombre
from partidos p
join resultados r on r.partido = p.codigo and p.codprv = r.codprv
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo
left join numelectos n on r.codprv = n.codprv and r.proceso = n.proceso and n.tipo = 'M' and r.partido = n.partido and po.codigo = n.circunscripcion
where
p.codprv = 13 and
r.proceso = 42 and
m.municipio = 175
/* Para evitar registros sin electos */
and n.circunscripcion is not null
group by p.codigo, p.nombre, electos, n.circunscripcion, po.nombre
order by po.nombre, 3 /*votos*/ desc, 4 /*electos*/ desc, p.nombre

Código SQL [-]
select p.codigo, p.nombre, coalesce(sum(r.votos), 0) votos, coalesce(n.electos, 0) electos, n.circunscripcion,
       po.nombre
from partidos p
join resultados r on r.partido = p.codigo and p.codprv = r.codprv
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo
left join numelectos n on r.codprv = n.codprv and r.proceso = n.proceso and n.tipo = 'M' and r.partido = n.partido and po.codigo = n.circunscripcion
where
p.codprv = 13 and
r.proceso = 42 and
m.municipio = 175
group by p.codigo, p.nombre, electos, n.circunscripcion, po.nombre
/* Para evitar registros sin electos */
having coalesce(n.electos, 0) > 0
order by po.nombre, 3 /*votos*/ desc, 4 /*electos*/ desc, p.nombre

duilioisola 13-11-2023 22:50:47

PD.

Después de ejecutar el script, todo iba muy lento.
He tenido que recaclular los índices para que todo vaya bien.

IbExpert tiene la opción de ir a DataBase-> Recompute celectivity of all Indeces

Básicamente recorre los índices de la base de datos y ejecuta SET STATISTICS INDEX [IndexName]:
Código SQL [-]
SET STATISTICS INDEX DISMES;

SET STATISTICS INDEX MUNMES;

SET STATISTICS INDEX PK_MESAS;

SET STATISTICS INDEX PK_NUMELECTOS;

SET STATISTICS INDEX PK_PARTIDOS;

SET STATISTICS INDEX PK_POBLACION;

SET STATISTICS INDEX PK_RESULTADOS;

Angel.Matilla 14-11-2023 11:21:48

Cita:

Empezado por duilioisola (Mensaje 553286)
He estado mirando las tablas...

Primera parte

:( Perdona por no haberte explicado las relaciones, pero has acertado en todas.

Angel.Matilla 14-11-2023 11:34:02

Cita:

Empezado por duilioisola (Mensaje 553287)
PD.

Después de ejecutar el script, todo iba muy lento.
He tenido que recaclular los índices para que todo vaya bien.

Muchísimas gracias pro tu ayuda. Has hecho un pleno. Sólo he tenido que cambiar una cosa para que me saque todos los municipios, pero el query es perfecto.

Por otra parte, sobre la velocidad de ejecución he de decirte que para sacar todos los municipios a mi en SQL Manager me ha tardado 62 milisegundos. Únicamente las lecturas de la tabla mesas se hacen sin usar índices; tengo que ver por qué.

duilioisola 14-11-2023 13:27:36

A mi también me va muy rápida la consulta, pero al principio los índices estaban desbalanceados (supongo que por el insert masivo del script) y todos tenínan un valor de 1 (o 0, no recuerdo bien).
Las estadísticas de los índices es una parte importante de lo que mira el planificador de SQL al hacer los JOINS.


Esto te devuelve las estadísticas de los índices y deberían tener valores lo más bajo posibles sin ser 0.
Código SQL [-]
select rdb$relation_name, rdb$index_name, rdb$statistics
from rdb$indices
where
/* Evito indices de sistema */
rdb$system_flag = 0
order by rdb$relation_name, rdb$index_name

Esto es lo que me devuelve ahora, después de ejeructar el "SET STATISTICS [indice]".
Código:

RDB$RELATION_NAME  RDB$INDEX_NAME  RDB$STATISTICS
-----------------  --------------  --------------
MESAS              DISMES          0,001355013577
MESAS              MUNMES          0,009803921916
MESAS              PK_MESAS        0,001355013577
NUMELECTOS          PK_NUMELECTOS    0,001915708766
PARTIDOS            PK_PARTIDOS      0,018518518656
POBLACION          PK_POBLACION    0,000017048846
RESULTADOS          PK_RESULTADOS    0,000008809486


Angel.Matilla 14-11-2023 20:12:25

Es decir que cuanto más bajo sea ese valor mejor está el índice. No lo sabía; todos los días se aprende algo.

Otra cosa: Si ejecuto el query para que me saque todos los municipios, cambiando la línea
Código SQL [-]
m.municipio = 175
por
Código SQL [-]
m.municipio = po.codigo
me ocurre una cosa que, al menos a mi, me llama la atención.
Table Operations:
+-----------------
Table Name | Index | Non-Index
| reads | reads
+--------------------------+-----------+
MESAS| 0 | 1.476 |
NUMELECTOS| 4.534 | 0 |
PARTIDOS| 5.786 | 0 |
POBLACION| 1.476 | 0 |
PROVINCIA| 5.786 | 0 |
RESULTADOS| 5.786 | 0 |

La tabla mesas tiene tres índices: la clave primaria (CodPrv + Codigo) y dos índices: uno por CodPrv y Municipio y el otro por todos los datos identificativos de la mesa. Y dado que las búsquedas en las que interviene la tabla Mesas se hacen por alguno de los campos indexados, prinicipalmente municipio y código de mesa), ¿por qué no se usan los índices para esas búsquedas?

duilioisola 14-11-2023 20:56:56

El número de los índices indica cuan específico es. Entiéndase cuan único es cada registro.
Si tienes una tabla ARTICULOS (EMPRESA, ARTICULO) y tienes los valores
Código:

1, ART1
1, ART2
1, ART3
1, ART4

un índice por EMPRESA tendrá estadística = 1, indicando que se repite para todos los registros
un índice por ARTICULO tendra estadística = 0,25, indicando que "se repite poco" (en este ejemplo nada) en todos los registros.
Por lo tanto, si el planificador de JOINs tiene la opción de usar uno de estos dos índices, preferirá el de artículo.

Nota: Un índice por EMPRESA+ARTICULO también tendra estadística = 0,25, indicando que "se repite poco" (en este ejemplo nada) en todos los registros.

Creo que estás haciendo el SQL de forma incorrecta.
Si no quieres filtrar por municipio, debes eliminar esa línea del WHERE.

Código SQL [-]
select p.codigo, p.nombre, coalesce(sum(r.votos), 0) votos, coalesce(n.electos, 0) electos, n.circunscripcion,
       po.nombre
from partidos p
join resultados r on r.partido = p.codigo and p.codprv = r.codprv
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo
left join numelectos n on r.codprv = n.codprv and r.proceso = n.proceso and n.tipo = 'M' and r.partido = n.partido and po.codigo = n.circunscripcion
where
p.codprv = 13 and
r.proceso = 42 
/* and m.municipio = 175 Muestra todos los municipios */ 
group by p.codigo, p.nombre, electos, n.circunscripcion, po.nombre
order by po.nombre, 3 /*votos*/ desc, 4 /*electos*/ desc, p.nombre

Suposición 1 - Agregas lo que mencionas al WHERE.
Si haces lo que que mencionas, estarás diciendo que muestre los registros donde el municipio de la mesa sea el municipio de la poblacion.
Esto ya está garantizado por los JOINs
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo

Solo le estarás complicando la vida al planificador.

Código SQL [-]
select p.codigo, p.nombre, coalesce(sum(r.votos), 0) votos, coalesce(n.electos, 0) electos, n.circunscripcion,
       po.nombre
from partidos p
join resultados r on r.partido = p.codigo and p.codprv = r.codprv
join mesas m on m.codprv = r.codprv and m.codigo = r.mesa
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo
left join numelectos n on r.codprv = n.codprv and r.proceso = n.proceso and n.tipo = 'M' and r.partido = n.partido and po.codigo = n.circunscripcion
where
p.codprv = 13 and
r.proceso = 42 
/* Muestra todos los municipios */ 
and m.municipio = po.codigo 
group by p.codigo, p.nombre, electos, n.circunscripcion, po.nombre
order by po.nombre, 3 /*votos*/ desc, 4 /*electos*/ desc, p.nombre


Suposición 2 - Quitas "m.municipio = po.codigo" del JOIN .
Si haces esto, estás cambiando los datos sobre los que haces los cálculos.
En ese caso, si tenemos en cuenta solo las tablas MESAS y POBLACION sería
Código SQL [-]
/* Original */
mesas m 
join poblacion po on p.codprv = po.codprv and m.municipio = po.codigo

/* Tu modificacion */
mesas m 
join poblacion po on p.codprv = po.codprv /*and m.municipio = po.codigo*/

En este caso cada mesa se uniría con todas las poblaciones y tendrías muchísimos registros más.
Prueba estos SQL:
Código SQL [-]
/* Esto te devuelve las mesas y su municipio*/
/* Devuelve 738 registros para la provincia 13 */
select m.codprv, m.codigo, m.municipio, po.codigo, po.nombre
from mesas m
join poblacion po on m.codprv = po.codprv and m.municipio = po.codigo
where
m.codprv = : prvins
order by m.codprv, m.codigo, m.municipio, po.codigo, po.nombre
Código SQL [-]
/* Esto te devuelve las mesas unidas a cada municipio (aunque no le corresponda) */
/* ATENCION - TARDARÁ MUCHO Y DEVOLVERA MILES DE REGISTROS */
/* Registros = 738 mesas x 58.655 poblaciones = 42.287.390 registros*/
select m.codprv, m.codigo, m.municipio, po.codigo, po.nombre
from mesas m
join poblacion po on m.codprv = po.codprv /* and m.municipio = po.codigo*/
where
m.codprv = : prvins
order by m.codprv, m.codigo, m.municipio, po.codigo, po.nombre


La franja horaria es GMT +2. Ahora son las 01:52:12.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi