Hola Lista, a ver si alguien me ilumina con este expediente X... Tengo
varias BBDD en postgres 9.1.X y las necesito a migrar a 9.5 o 9.6 pero
detecto un problema que no consigo solucionar.

Resumiendo la demostración que hay mas abajo, busco un registro en UTC de
una fecha sin problemas y al cambiar de TIMEZONE si la tabla tiene indice
en PG 9.5 o PG 9.6 NO encuentra el Registro.

La BBDD tanto en 9.1, 9.5 o 9.6 las tengo en UTC, al igual que el sistema
operativo.


En una 9.1 las siguientes sentencias FUNCIONAN con el cambio de TIMEZONE.

psql -d demo -U demo

Demostramos que estamos en UTC
demo=> *show timezone;*
 TimeZone
----------
 UTC
(1 row)

*create table a ( fecha timestamptz, numero numeric(10), codigo varchar(18)
);*

*alter table a add constraint a_pk primary key (fecha,numero,codigo);*
*insert into a values (current_timestamp, 2010, '004694052615675402');*

demo=> *select * from a;*
             fecha             | numero |       codigo
-------------------------------+--------+--------------------
 2016-10-18 13:37:52.287151+00 |   2010 | 004694052615675402
(1 row)

Localiza el registro sin problemas
demo=> *select * from a where fecha AT TIME ZONE 'UTC' = TIMESTAMP WITHOUT
TIME ZONE '2016-10-18 13:37:52.287151+00' and numero = 2010 and codigo =
'004694052615675402';*
             fecha             | numero |       codigo
-------------------------------+--------+--------------------
 2016-10-18 13:37:52.287151+00 |   2010 | 004694052615675402

Este es el explain y usa el indice.
demo=> *explain analyze select * from a where fecha AT TIME ZONE 'UTC' =
TIMESTAMP WITHOUT TIME ZONE '2016-10-18 13:37:52.287151+00' and numero =
2010 and codigo = '004694052615675402';*
                                                QUERY PLAN
----------------------------------------------------------------------------------------------------------
 Index Scan using a_pk on a  (cost=0.00..22.97 rows=1 width=46) (actual
time=0.015..0.017 rows=1 loops=1)
   Index Cond: ((numero = 2010::numeric) AND ((codigo)::text =
'004694052615675402'::text))
   Filter: (timezone('UTC'::text, fecha) = '2016-10-18
13:37:52.287151'::timestamp without time zone)
 Total runtime: 0.049 ms
(4 rows)

Cambiamos el TIMEZONE y la MISMA consulta encuentra el registro con *ÉXITO* ya
que forzamos el TIMEZONE ( esto en PG9.5 - 9.6 NO FUNCIONA)
demo=> *SET TIMEZONE TO 'America/Santo_Domingo';*
select * from a where fecha AT TIME ZONE 'UTC' = TIMESTAMP WITHOUT TIME
ZONE '2016-10-18 13:37:52.287151+00' and numero = 2010 and codigo =
'004694052615675402';
             fecha             | numero |       codigo
-------------------------------+--------+--------------------
 2016-10-18 09:37:52.287151-04 |   2010 | 004694052615675402

demo=> *explain analyze select * from a where fecha AT TIME ZONE 'UTC' =
TIMESTAMP WITHOUT TIME ZONE '2016-10-18 13:37:52.287151+00' and numero =
2010 and codigo = '004694052615675402';*
                                                QUERY PLAN
----------------------------------------------------------------------------------------------------------
 Index Scan using a_pk on a  (cost=0.00..22.97 rows=1 width=46) (actual
time=0.018..0.021 rows=1 loops=1)
   Index Cond: ((numero = 2010::numeric) AND ((codigo)::text =
'004694052615675402'::text))
   Filter: (timezone('UTC'::text, fecha) = '2016-10-18
13:37:52.287151'::timestamp without time zone)
 Total runtime: 0.045 ms
(4 rows)


Misma prueba en postgres 9.5 o 9.6

psql -d demo -U demo

Demostramos que estamos en UTC
demo=> *show timezone;*
 TimeZone
----------
 UTC
(1 row)

*create table a ( fecha timestamptz, numero numeric(10), codigo varchar(18)
);*

*alter table a add constraint a_pk primary key (fecha,numero,codigo);*
*insert into a values (current_timestamp, 2010, '004694052615675402');*

demo=> *select * from a;*
             fecha             | numero |       codigo
-------------------------------+--------+--------------------
 2016-10-18 14:32:21.433333+00 |   2010 | 004694052615675402

localiza el registro sin problemas
demo=> *select * from a where fecha AT TIME ZONE 'UTC' = TIMESTAMP WITHOUT
TIME ZONE '2016-10-18 14:32:21.433333+00' and numero = 2010 and codigo =
'004694052615675402';*
             fecha             | numero |       codigo
-------------------------------+--------+--------------------
 2016-10-18 14:32:21.433333+00 |   2010 | 004694052615675402
(1 row)

Este es el explain y usa el indice.
demo=> *explain analyze select * from a where fecha AT TIME ZONE 'UTC' =
TIMESTAMP WITHOUT TIME ZONE '2016-10-18 14:32:21.433333+00' and numero =
2010 and codigo = '004694052615675402';*
                                               QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using a_pk on a  (cost=0.15..8.17 rows=1 width=46) (actual
time=0.022..0.023 rows=1 loops=1)
   Index Cond: ((fecha OPERATOR(pg_catalog.=) '2016-10-18
14:32:21.433333'::timestamp without time zone) AND (numero =
'2010'::numeric) AND (codigo = '004694052615675402'::text))
   Heap Fetches: 1
 Planning time: 0.135 ms
 Execution time: 0.061 ms
(5 rows)

Cambiamos el TIMEZONE y la MISMA consulta encuentra el registro con *ÉXITO* ya
que forzamos el TIMEZONE ( esto en PG9.5 - 9.6 NO FUNCIONA)
demo=> *SET TIMEZONE TO 'America/Santo_Domingo';*

Dónde esta el registro ? No lo encuentra --  LA CULPA LA TIENE EL INDICE...
demo=> select * from a where fecha AT TIME ZONE 'UTC' = TIMESTAMP WITHOUT
TIME ZONE '2016-10-18 14:32:21.433333+00' and numero = 2010 and codigo =
'004694052615675402';
 fecha | numero | codigo
-------+--------+--------
(0 rows)

Como podemos ver usa la PK para NO Localizar el registro
demo=> explain analyze select * from a where fecha AT TIME ZONE 'UTC' =
TIMESTAMP WITHOUT TIME ZONE '2016-10-18 14:32:21.433333+00' and numero =
2010 and codigo = '004694052615675402';

        QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using a_pk on a  (cost=0.15..8.17 rows=1 width=46) (actual
time=0.013..0.013 rows=0 loops=1)
   Index Cond: ((fecha OPERATOR(pg_catalog.=) '2016-10-18
14:32:21.433333'::timestamp without time zone) AND (numero =
'2010'::numeric) AND (codigo = '004694052615675402'::text))
   Heap Fetches: 0
 Planning time: 0.120 ms
 Execution time: 0.041 ms
(5 rows)

Borramos el índice
demo=> alter table a drop constraint a_pk;
ALTER TABLE

Buscamos con EXITO sin INDICE
demo=> select * from a where fecha AT TIME ZONE 'UTC' = TIMESTAMP WITHOUT
TIME ZONE '2016-10-18 14:32:21.433333+00' and to_varchar(numero) = '2010'
and codigo = '004694052615675402';
             fecha             | numero |       codigo
-------------------------------+--------+--------------------
 2016-10-18 10:32:21.433333-04 |   2010 | 004694052615675402
(1 row)

Demostración que ahora lo localiza con un secuencial Scan
demo=> explain analyze select * from a where fecha AT TIME ZONE 'UTC' =
TIMESTAMP WITHOUT TIME ZONE '2016-10-18 14:32:21.433333+00' and
to_varchar(numero) = '2010' and codigo = '004694052615675402';

                              QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on a  (cost=10000000000.00..10000000037.50 rows=1 width=46)
(actual time=0.018..0.020 rows=1 loops=1)
   Filter: (((fecha)::timestamp without time zone = '2016-10-18
14:32:21.433333'::timestamp without time zone) AND ((codigo)::text =
'004694052615675402'::text) AND (((numero)::character varying(20))::text =
'2010'::text))
 Planning time: 0.141 ms
 Execution time: 0.048 ms
(4 rows)

Siento el tocho pero no doy con la solución. He probado reindexar ,
analizar estadísticas y nada, cuando usa el índice no encuentro el registro.

Muchas Gracias.
Alex.

Responder a