Mostrando las entradas con la etiqueta db2. Mostrar todas las entradas
Mostrando las entradas con la etiqueta db2. Mostrar todas las entradas

lunes, julio 26, 2010

¿ocupa o no el indice?

Este es uno de los blogs que me gusta seguir http://www.depesz.com/ habla sobre todo de queries sql y esas cosas, pero todo basado en postgres. Me gusta seguirlo y hacer lo posible por imitar sus problemas pero en db2, he aqui un intento:HOW TO ORDER BY SOME RANDOM – QUERY DEFINED – VALUES?

Esta funcion viene por defecto en postgres y se ocupa demasiado, te da muchas ventajas no la eh optimizado ni nada, y por ahi pienso que se puede usar metaprogramación para que quede más rápida, pero ahí va.

CREATE OR REPLACE FUNCTION generate_series (ini integer, fin integer, inc integer)
RETURNS TABLE (val integer)
LANGUAGE SQL
READS SQL DATA
NO EXTERNAL ACTION
DETERMINISTIC
RETURN
with dummy(id) as (
select generate_series.ini from sysibm.sysdummy1
union all
SELECT id + generate_series.inc FROM dummy WHERE id < generate_series.fin
)
select id from dummy@

Las pruebas de rigor

select * from TABLE(generate_series(1,20,2)) as X@
--SELECT substr(funcschema, 1, 12) as funcs, substr(funcname, 1, 30) as func from syscat.functions ORDER BY 1,2 @

Empezamos con el tutorial.

CREATE TABLE test_data (
id INT NOT NULL PRIMARY KEY, --te pide afuerza el not null
codename VARCHAR(254)
)@

SELECT * FROM test_data @

INSERT INTO test_data (id, codename)
SELECT i.val, 'codename for:' || i.val
FROM TABLE(generate_series(1,100,1)) as i @ -- pequeño truco, hay que poner TABLE si no no jala

Y este es el query que nos interesa, muy sencillo, pero me trae sus consecuencias.

SELECT  id, cast(codename as varchar(15)) FROM test_data WHERE id IN (3, 71, 5, 16);@
ID 2
----------- ---------------
3 codename for:3
71 codename for:71
5 codename for:5
16 codename for:16
* 4 row(s) fetched, 4 row(s) output.
* Elapsed Time is: 0.001058 seconds

Y sorpresa, los valores nos los da ya ordenados. No hay que hacer más trucos, pero a mi experiencia esto esta mal.


SELECT id, cast(codename as varchar(15)) FROM test_data WHERE id IN (71, 3, 5, 16);@
ID 2
----------- ---------------
71 codename for:71
3 codename for:3
5 codename for:5
16 codename for:16
* 4 row(s) fetched, 4 row(s) output.

Pequeñas variaciones y hace lo mismo. Ahora bien, ¿esto esta bien? segun yo no, los datos deberian de aparecer de acuerdo al orden de inserción, si no abría que asumir que la db esta haciendo algo que no le hemos indicado, en este caso ordenar. Pero el error sigue siendo otro, en esta consulta no se ocupa el indice
De Miguel Angel Huerta Gonzalez



SELECT id, cast(codename as varchar(15)) FROM test_data WHERE id IN (71, 3, 5, 16, 27, 19, 2);@
ID 2
----------- ---------------
2 codename for:2
3 codename for:3
5 codename for:5
16 codename for:16
19 codename for:19
27 codename for:27
71 codename for:71
* 7 row(s) fetched, 7 row(s) output.
* Elapsed Time is: 0.050610 seconds


Y aqui esta lo que esperamos!!!, porque lo hizo? porque hay más datos?, si parece que ocupa el indice solo cuando hay muchos datos. Este es un comportamiento normal, las base de datos solo van al índice cuando hay que ir al índice.

De Miguel Angel Huerta Gonzalez


Imaginemos el seq scan, va comparando 1 por 1, y es por esto que los datos nos los da como aparecen en el IN. Cuando va al indice, rearma la consulta y los datos no los trae de acuerdo a como aparecen en el ínce.

Realizé otra prueba en sqlite, donde solo inserte 10 datos y ahi lo tienen, los datos aparecen en el orden del indice y no en el de insercion como pensaba...


sqlite> SELECT * FROM test_data WHERE id IN (3, 1, 5, 6);
1|codename for 1
3|codename for 3
5|codename for 5
6|codename for 6
sqlite>

-- Un select sin nada si nos da por orden de insercion.
sqlite> SELECT * FROM test_data ;
10|codename for 10
9|codename for 9
8|codename for 8
7|codename for 7
6|codename for 6
5|codename for 5
4|codename for 4
3|codename for 3
2|codename for 2
1|codename for 1

-- Mis intentos de sacar un explain en consola no prosperaron
-- EXPLAIN PLAN SET QUERYNO = 13
-- EXPLAIN PLAN SET QUERYNO = 1 FOR SELECT * FROM test_data WHERE id IN (3, 71, 5, 16);

jueves, julio 15, 2010

vim and db2

Una de las herramientas que más me gusta y la que más me critican es el uso de VIM, pero estoy acostumbrado a usar máquinas poco potentes (mi actual máquina es una mini acer aspire one) y el ahorro de memoria es muy apreciado para mi.

Actualmente me estoy especializando en db2 y como sabrán todas sus herramientas visuales de administración corren en java (malo para la memoria) así que ¿por qué no integrar db2 y vim?. Y como le pasa a mi amigo Toño, con casi todas sus buenas ideas, ya esta inventado. No tan solo se puede conectar a db2, sino que soporta varias bases de datos, el plugin de vim es dbext.vim, después de leer la documentación y seguir el :h db2ext-tutorial, me tiraba el siguiente error:

Connection: T(DB2) D(sample) at 22:28

*** Invalid argument(s) for command line option

*** For option "-s"

* Type 'db2batch -h' for help.

/bin/bash: -f: no se encontró la orden

To change connection parameters:

:DBPromptForBufferParameters

Or

:DBSetOption user|passwd|dsnname|srvname|dbname|host|port|...=<value>

:DBSetOption user=tiger:passwd=scott

Last command(rc=127):

db2batch -q off -s off-d sample -l ; -f /tmp/vZbICSm/dbext.sql

Last SQL:

SELECT id FROM customer;

Grave error, pero hay que fijarnos bien en el comando que ejecuta:

db2batch -q off -s off-d sample -l ; -f /tmp/vZbICSm/dbext.sql

Que tiene de malo, varias cosas:

-s off-d sample :No hay espacio entre off-d

-l ; :en linux ; tiene un significado especial asi que hay que encerrarlo entre "" o de plano quitarlo

Leyendo un poco el código fuente del plugin .vim/autoload/dbext.vim, vemos la falla, la cual se localiza en las variables:

g:dbext_default_DB2_cmd_options.'':'-q off -s off'

g:dbext_default_DB2_cmd_terminator.'':';'

Así que para no aburrirles tanto ejecutamos en vim:

:let g:dbext_default_DB2_cmd_options = '-q off -s off '

:let dbext_default_DB2_cmd_terminator = ''

y ya tendremos funcionado nuestro plugin.

Ver video con la nostalgia de mis tecladazos!!!

Edit: no se pudo subir el audio...

martes, julio 06, 2010

Error CLI0622E

Al momento de instalar DB2 express - C no podía acceder a las herramientas gráficas, como el command center (db2cc), debido al error cli0622e:

db2inst1@macuile:~$ db2 ? CLI0622E

CLI0622E Error accessing JDBC administration service extensions.

Casi toda la ayuda en google dice que el error es debido a que no tenemos los driver JDBC en nuestro directorio $inst/sqllib, pero en mi caso si estaban todos.

El problema huele a cosa de java, y lo es:

db2inst1@macuile:~$ db2 get dbm cfg | grep JDK_PATH
Java Development Kit installation path (JDK_PATH) = /usr/lib/jvm/java-6-sun/

No recuerdo cual era mi JDK_PATH por defecto, pero tampoco funcionaba con eso
¿por que?
Supongo que porque debian no está soportado tal cual en la instalación, se quedan muchas rutas por defectos y alguno que otro problema concerniente a esta lucha entre las distribuciones. Además de que no todas las implementaciones del JRE son iguales, algo habrá hecho IBM con es jdk

La solucíon, encontrar el JRE que instala DB2, en mi caso
/home/ibm/db2/V9.7/java/jdk32/

Ejecutar el siguiente comando:
$ db2 update dbm cfg using JDK_PATH /home/ibm/db2/V9.7/java/jdk32/

Esto tendría que hacerse por instancia.

Datos:
db2inst1@macuile:~$ db2level
DB21085I Instance "db2inst1" uses "32" bits and DB2 code release "SQL09071"
with level identifier "08020107".
Informational tokens are "DB2 v9.7.0.1", "s091114", "IP23033", and Fix Pack
"1".
Product is installed at "/home/ibm/db2/V9.7".

miguel@macuile:~/Desktop$ uname -a
Linux macuile 2.6.32-3-686 #1 SMP Thu Feb 25 06:14:20 UTC 2010 i686 GNU/Linux

miguel@macuile:~/Desktop$ cat /etc/debian_version
squeeze/sid


sábado, marzo 29, 2008

split_part in db2

En vista de que no encontre ninguna funcion de db2 8.x.x que hiciera un split en un campo varchar decidi implementar una, lo que hace es dividir un campo varchar separado por algun caracter.


SELECT split_part('pru|ba|prueba','|',2) FROM sysibm.sysdummy1;
1
----
ba


he aqui el codigo:


CREATE FUNCTION split_part ( string varchar(60),caracter varchar(5), position integer )
RETURNS varchar(20)
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
WITH series2(seq) AS
(
VALUES (1)
UNION ALL
SELECT seq + 1 FROM series2 WHERE seq < length(string)+2
),
series(seq) as ( SELECT DISTINCT seq FROM series2 ORDER BY seq)
SELECT final
FROM ( SELECT substr(string,S1.seq,min(S2.seq) - S1.seq -1) as final,
row_number() over() as row_num
FROM series AS S1, series AS S2
WHERE substr (caracter || string || caracter,S1.seq ,1) = caracter
AND substr (caracter || string || caracter, S2.seq , 1) =caracter
AND S1.seq < S2.seq
GROUP BY string, S1.seq) as temp2
WHERE row_num = position;


En la linea 14 Sequence(seq) as ( select distinct seq from Sequence2 order by seq) se hace por optimización, y la verdad no se si se pudiera meter adentro de la primera tabla recursiva, si no se hace un ordenamiento entonces el join de la linea 21 AND S1.seq < S2.seq seria hecho secuencialmente, lo que alentaria el proceso que de por si ocupa demasiada fuerza bruta.

Claro que con postgres 8.3 las cosas son más faciles

miguel=# explain select split_part(name,'|',2) from test_names ;
QUERY PLAN
-----------------------------------------------------------
Seq Scan on test_names (cost=0.00..1.05 rows=4 width=13)
(1 row)


Lo unico malo es que no tengo un servidor de db2 como para hacer pruebas más certeras y para entenderle más a los datos que arroja su optimizador, cosa que no he podido comprender del todo.