domingo, 31 de marzo de 2013

ORA-02393

Este ejemplo está probado en Oracle 11.2.0.2.7 y muestra come se puede limitar el tiempo de CPU de una consulta SQL. Antes de empezar, hay que verificar que RESOURCE_LIMIT sea TRUE. Si no se hace esto, Oracle no impone los límites: 

SQL> alter session set nls_language = 'SPANISH'
  2  /
 
Sesion modificada.
 

SQL> alter system set resource_limit = true
  2  /
 
Sistema modificado.
 
SQL>

Luego es necesario crear un perfil que limitará el tiempo de CPU a un segundo (el valor es suministrado en centésimas de segundo): 

SQL> create profile para_andrew
  2  limit cpu_per_call 100
  3  /
 
Perfil creado.
 
SQL>

Entonces debemos tener un usuario con este perfil:

SQL> create user andrew identified by reid
  2  profile para_andrew
  3  /
 
Usuario creado.
 
SQL> grant create session,
  2        alter session,
  3        select any dictionary to andrew
  4  /
 
Concesion terminada correctamente.
 
SQL> conn andrew/reid
Connected.
SQL> alter session set nls_language = 'SPANISH'
  2  /
 
Sesion modificada.
 
SQL>

Medimos el tiempo de CPU al principio de la manera siguiente:

SQL> select a.value/100
  2  from v$mystat a, v$sysstat b
  3  where a.statistic# = b.statistic#
  4  and b.name = 'CPU used by this session'
  5  /
 
A.VALUE/100
-----------
        .01
 
SQL>

Luego ejecutamos una consulta que empleará más de un segundo de tiempo de CPU: 

SQL> select count(*)
  2  from dba_tables a, dba_tables b
  3  /
from dba_tables a, dba_tables b
     *
ERROR en linea 2:
ORA-02393: ha excedido el limite de llamadas para uso
de CPU
 
SQL>

La consulta falla con un error ORA-02393. Entonces vemos que el tiempo de CPU de la sesión sea aproximadamente un segundo más:

SQL> select a.value/100
  2  from v$mystat a, v$sysstat b
  3  where a.statistic# = b.statistic#
  4  and b.name = 'CPU used by this session'
  5  /
 
A.VALUE/100
-----------
        1.2
 
SQL>

En inglés / in English 

sábado, 30 de marzo de 2013

Como se Puede Ver el Juego de Carácteres de una Base de Datos

Se puede ver el juego de carácteres empleado por una base de datos de la manera siguiente: 

SQL> l
  1  SELECT VALUE$
  2  FROM SYS.PROPS$
  3* WHERE NAME = 'NLS_CHARACTERSET'
SQL> /

VALUE$
--------------------
WE8MSWIN1252

SQL>

El ejemplo arriba funciona para usuarios que tienen los derechos de ver los objetos de SYS. Si tu usuario no puede ver los objetos de SYS, se puede ver el juego de carácteres de este modo: 

SQL> conn / as sysdba
Conectado.
SQL> create user andrew
  2  identified by reid
  3  /

Usuario creado.

SQL> grant create session to andrew
  2  /

Concesion terminada correctamente.

SQL> conn andrew/reid
Conectado.
SQL> select value$
  2  from sys.props$
  3  where name = 'NLS_CHARACTERSET'
  4  /
from sys.props$
         *
ERROR en linea 2: ORA-00942: la tabla o vista no existe

SQL> select nls_charset_name(nls_charset_id('CHAR_CS'))
  2  from dual
  3  /

NLS_CHARSET_NAME(NLS_CHARSET_ID('CHAR_CS')) ---------------------------------------------
WE8MSWIN1252

SQL> select sys_context('userenv','LANGUAGE')
  2  from dual
  3  /

SYS_CONTEXT('USERENV','LANGUAGE')
-----------------------------------
SPANISH_AMERICA.WE8MSWIN1252

SQL>

jueves, 28 de marzo de 2013

Como se Puede Ver la Versión de un Cliente Oracle

Quería saber la versión de un cliente Oracle desde Windows. Abrí un Command Prompt. Luego escribí a máquina tnsping sin parámetros y empleé la tecla Enter / Return. Entonces vi la versión (10.2.0.4.0 en este caso). También vi que el cliente Oracle era 32-bit y no 64-bit. Haz clic en la imagen para verla en su tamaño original:

Las ideas que siguen vinieron de Laurent Schneider. También se puede ver la versión de un cliente Oracle con sqlplus -v:

Tru64 > sqlplus -v

SQL*Plus: Release 9.2.0.7.0 - Production

Tru64 >

H:\>sqlplus -v

SQL*Plus: Release 10.2.0.4.0 - Production

H:\>

Solaris > sqlplus -v

SQL*Plus: Release 11.2.0.2.0 Production

Solaris >

Laurent dice también que la versión mostrada por la herramienta (sqlplus, tnsping etc) no será correcta si la herramienta no fue cambiada cuando el propio cliente fue actualizado.

En inglés / in English

domingo, 24 de marzo de 2013

Connected to an idle instance y ORA-01034

Hallé este ejemplo, escrito por Kamran Agayev, aquí y decidí traducirlo en español. Tenía una base de datos en un servidor UNIX:

ORCL /export/home/oracle > ps -ef|grep ORCL|grep -v grep
  oracle   840  1348  0  14:45:17 ?  0:00 ora_s000_ORCL
  oracle   814  1348  0  14:45:16 ?  0:00 ora_dia0_ORCL
  oracle   798  1348  0  14:45:13 ?  0:00 ora_pmon_ORCL
  oracle   818  1348  0  14:45:16 ?  0:00 ora_dbw0_ORCL
  oracle  1019  1348  0  14:45:42 ?  0:00 ora_q000_ORCL
  oracle   800  1348  0  14:45:14 ?  0:00 ora_psp0_ORCL
  oracle  1005  1348  0  14:45:36 ?  0:01 ora_cjq0_ORCL
  oracle   824  1348  0  14:45:16 ?  0:00 ora_ckpt_ORCL
  oracle   833  1348  0  14:45:17 ?  0:00 ora_mmnl_ORCL
  oracle   831  1348  0  14:45:17 ?  0:01 ora_mmon_ORCL
  oracle   808  1348  0  14:45:15 ?  0:00 ora_gen0_ORCL
  oracle   829  1348  0  14:45:17 ?  0:00 ora_reco_ORCL
  oracle   802  1348  0  14:45:15 ?  0:00 ora_vktm_ORCL
  oracle   810  1348  0  14:45:15 ?  0:00 ora_diag_ORCL
  oracle   827  1348  0  14:45:16 ?  0:00 ora_smon_ORCL
  oracle   837  1348  0  14:45:17 ?  0:00 ora_d000_ORCL
  oracle   820  1348  0  14:45:16 ?  0:00 ora_lgwr_ORCL
  oracle   816  1348  0  14:45:16 ?  0:00 ora_mman_ORCL
  oracle   812  1348  0  14:45:15 ?  0:00 ora_dbrm_ORCL
  oracle  1023  1348  0  14:45:42 ?  0:00 ora_q001_ORCL
  oracle   963  1348  0  14:45:32 ?  0:00 ora_qmnc_ORCL
ORCL /export/home/oracle >


Intenté conectarme a la base de datos:

ORCL /export/home/oracle > sqlplus / as sysdba

SQL*Plus: Release 10.2.0.3.0 - Production on Thu Dec 13 16:57:48 2012

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.

Connected to an idle instance.

SQL> select name from v$database;
select name from v$database
*
ERROR at line 1:
ORA-01034: ORACLE not available
Process ID: 0
Session ID: 0 Serial number: 0

SQL>


Vi el mensaje Connected to an idle instance. Éste suele querer decir que la base de datos sea cerrada pero de veras ya estaba abierta. Miré mi variable $ORACLE_HOME:

ORCL /export/home/oracle > echo $ORACLE_HOME
/oracle/app/oracle/product/11.2.0.2.7/
ORCL /export/home/oracle >


La barra (/) al fin no me parecío correcta y por eso la eliminé:

ORCL /export/home/oracle > export ORACLE_HOME=/oracle/app/oracle/product/11.2.0.2.7
ORCL /export/home/oracle > echo $ORACLE_HOME
/oracle/app/oracle/product/11.2.0.2.7
ORCL /export/home/oracle >


Luego me conecté a la base de datos sin problemas:

ORCL /export/home/oracle > sqlplus / as sysdba

SQL*Plus: Release 10.2.0.3.0 - Production on Thu Dec 13 16:59:18 2012

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.

Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> select name from v$database;

NAME
---------
ORCL

SQL>

sábado, 23 de marzo de 2013

SQL*Loader y ORA-01480

Probé este ejemplo en Oracle 11.2.0.2.7 en una máquina Solaris. Creé una fila de control para SQL*Loader. El nombre de la tabla dentro de esta fila tenía más de 30 carácteres: 

ORCL > cat andrew.ctl
load data
infile 'andrew.dat'
into table andrew7890123456789012345678901
fields terminated by ','
(col1, col2, col3)
ORCL >

Luego cuando intenté a emplear SQL*Loader, tuve un error ORA-01480: 

ORCL > sqlldr / control=andrew.ctl

SQL*Loader: Release 11.2.0.2.0 - Production on Thu Feb 7 15:57:48 2013

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

SQL*Loader-704: Internal error: ulmtsyn: OCIStmtExecute(tabhp) [1480]
ORA-01480: falta el valor nulo final del valor de enlace STR
ORCL >

Reduje la longitud del nombre a 30 carácteres y el error desapareció.

jueves, 14 de marzo de 2013

La Diferencia Entre Select Count(*) y Select Count(Nombre-de-Columna)

Hallé este ejemplo, escrito por Tanel Poder, aquí y decidí traducirlo para los hispanohablantes. Lo probé en Oracle 11.2.0.1.0. Hay una diferencia entre select count(*) o select count(constante) y select count(nombre-de-columna): 

SQL> select count(*) from v$session
  2  /

  COUNT(*)
----------
       513

SQL> select count(123) from v$session
  2  /

COUNT(123)
----------
       513

SQL> select count(username) from v$session
  2  /

COUNT(USERNAME)
---------------
            487

SQL> 

Select count(*) y select count(constante) cuentan todas las líneas que ven pero select count(nombre-de-columna) cuenta sólo las líneas donde columna no sea null. Si cambiamos el select count(*) o el select count(123) para contar sólo las líneas donde username no sea null, el resultado que vemos es igual al resultado del select count(username): 

SQL> select count(*) from v$session
  2  where username is not null
  3  /

 COUNT(*)
----------
       487

SQL> select count(123) from v$session
  2  where username is not null
  3  /

COUNT(123)
----------
       487

SQL>

Y si cambiamos el select count(username) para incluir las líneas donde username sea null, el resultado que vemos es igual a los resultados del select count(*) o del select count(123): 

SQL> select count(nvl(username,'blah'))
  2  from v$session
  3  /

COUNT(NVL(USERNAME,'BLAH'))
---------------------------
                        513

SQL>

viernes, 8 de marzo de 2013

V$SGASTAT

Se puede emplear la consulta siguiente para ver el tamaño de la memoria libre en una base de datos. La ejecuté en Oracle 11.1.0.6.0:

SQL> l
  1  select bytes from v$sgastat
  2  where pool = 'shared pool'
  3* and name = 'free memory'
SQL> /

     BYTES
----------
 390505176

SQL>

Si esta cifra permanece alta y el servidor no tiene mucha memoria, es posible reducir el tamaño del shared pool. Luego se puede reutilizar la memoria en otra parte.

martes, 5 de marzo de 2013

La Supresión Involuntaria de Índices

En estos dos ejemplos, verificados en Oracle 10, muestro la supresión involuntaria de un índice:

SQL> alter session set nls_language = 'SPANISH'
  2  /

Sesion modificada.

SQL> create table my_data
  2  as select object_id, object_name
  3  from dba_objects
  4  /

Tabla creada.

SQL>

Para empezar el primer ejemplo, he creado una tabla. Su primera columna se llama object_id y es de tipo number: 

SQL> desc my_data
Nombre                     ?Nulo?   Tipo
-------------------------- -------- ------------------ OBJECT_ID                           NUMBER OBJECT_NAME                         VARCHAR2(128)

SQL>

Entonces creo un índice en la columna object_id: 

SQL> create index my_index
  2  on my_data(object_id)
  3  /

Indice creado.

SQL>

Hago una consulta en la columna object_id que es de tipo number. Normalmente debería compararla con otro campo del mismo tipo, por ejemplo 51526  pero la comparo con ‘51526’. No obstante, el índice funciona todavía: 

SQL> set autotrace on
SQL> select count(*) from my_data
  2  where object_id = '51526'
  3  /

  COUNT(*)
----------
         1

Plan de Ejecucion
----------------------------------------------------------
Plan hash value: 425162582

------------------------------------------------------------------------------
| Id  | Operation         | Name     |  Rows | Bytes | Cost (%CPU)| Time     |   ------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     1 |    13 |     1   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |          |     1 |    13 |            |          |
|*  2 |   INDEX RANGE SCAN| MY_INDEX |     1 |    13 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): ---------------------------------------------------

   2 - access("OBJECT_ID"=51526)

 Note
 -----
    - dynamic sampling used for this statement

Estadisticas
----------------------------------------------------------
         32  recursive calls
          0  db block gets
         79  consistent gets
          1  physical reads
          0  redo size
        429  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> set autotrace off
SQL> drop table my_data
  2  /

Tabla borrada.

SQL>

El segundo ejemplo es un poco diferente: 

SQL> create table my_data
  2  as select object_id, object_name
  3  from dba_objects where 1 = 2
  4  /

Tabla creada.

SQL> alter table my_data modify
  2  (object_id varchar2(10))
  3  /

Tabla modificada.

SQL>

Esta vez, la columna object_id es de tipo varchar2(10): 

SQL> desc my_data
Nombre                     ?Nulo?   Tipo
-------------------------- -------- ------------------ OBJECT_ID                           VARCHAR2(10) OBJECT_NAME                         VARCHAR2(128)

SQL>

Pero la tabla contiene los mismos datos y el mismo índice: 

SQL> insert into my_data
  2  select object_id, object_name
  3  from dba_objects
  4  /

49752 filas creadas.

SQL> create index my_index
  2  on my_data(object_id)
  3  /

Indice creado.

SQL>

Hago una consulta en la columna object_id que es de tipo varchar2(10). Normalmente debería compararla con otro campo del mismo tipo, por ejemplo ‘51526’ pero la comparo con 51526. Esta vez el índice no funciona: 

SQL> set autotrace on
SQL> select count(*) from my_data
  2  where object_id = 51526
  3  /

  COUNT(*)
----------
         1

Plan de Ejecucion
----------------------------------------------------------
Plan hash value: 2558507361

------------------------------------------------------------------------------
| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |     1 |     7 |    57   (4)| 00:00:01 |
|   1 |  SORT AGGREGATE    |         |     1 |     7 |            |          |
|*  2 |   TABLE ACCESS FULL| MY_DATA |     3 |    21 |    57   (4)| 00:00:01 |
------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): ---------------------------------------------------

El problema es que Oracle quiere emplear to_number para cambiar cada registro antes de hacer la consulta: 

   2 - filter(TO_NUMBER("OBJECT_ID")=51526)

Note
-----
   - dynamic sampling used for this statement

Estadisticas
----------------------------------------------------------
         28  recursive calls
          0  db block gets
        303  consistent gets
          0  physical reads
          0  redo size
        429  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>

Si queremos emplear el índice en este segundo ejemplo, tenemos que cambiar la consulta de la manera siguiente: 

SQL> select count(*) from my_data
  2  where object_id = '51526'
  3  /

  COUNT(*)
----------
         1

Plan de Ejecucion
----------------------------------------------------------
Plan hash value: 425162582

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     1 |     7 |     1   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |          |     1 |     7 |            |          |
|*  2 |   INDEX RANGE SCAN| MY_INDEX |     1 |     7 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): ---------------------------------------------------

    2 - access("OBJECT_ID"='51526')

Note
-----
   - dynamic sampling used for this statement

Estadisticas
----------------------------------------------------------
          9  recursive calls
          0  db block gets
         59  consistent gets
          1  physical reads
          0  redo size
        429  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>

Si queremos emplear un índice, aquí está una sugerencia que viene de estos ejemplos:
Si tenemos una columna de tipo number, puede ser posible compararla con un número entre comillas por ejemplo ‘123’. Pero si tenemos una columna de tipo varchar2 y queremos compararla con un número, debemos poner el número entre comillas por ejemplo ‘123’.

domingo, 3 de marzo de 2013

Como se Puede Contar las Filas que Tengan un Nulo en una Columna

No se puede emplear = NULL para contar los valores nulos en una columna. Es necesario usar IS NULL. Para empezar, debemos hallar una tabla o una vista que tenga una columna con una mezcla de valores y valores nulos. Entonces contamos los valores nulos con la función NVL:

SQL> select count(*) from dba_tab_comments
  2  where nvl(comments,'NULL') = 'NULL'
  3  /

  COUNT(*)
----------
      2354

SQL>

Luego utilizamos IS NULL para contarlos otra vez. La respuesta es igual:

SQL> select count(*) from dba_tab_comments
  2  where comments is null
  3  /

  COUNT(*)
----------
      2354

SQL>

Por fin intentamos a contar los valores nulos empleando = NULL pero esto no los halla:

SQL> select count(*) from dba_tab_comments
  2  where comments = null
  3  /

  COUNT(*)
----------
         0

SQL>