Novo OCP Oracle!

setembro 2nd, 2010 por Flávio Soares

Como já disse uma vez Júlio César: “Veni, vidi, vici

Ontem fui para são paulo, fiz a prova e passei !

Desde os 15 anos de idade estudando Oracle e com 21, já ter 3 certificações é para ficar alegre não é : )
Próxima etapa? RAC Administrator Certified Expert.

Configurando raw discos em RHEL5

agosto 26th, 2010 por Flávio Soares

Vou demonstrar aqui, como podemos usar o UDEV para criar raw devices no Red Hat Enterprise Linux 5. Raw Devices é dispositivos sem formatações, muito utilizados para instâncias Oracle ASM.

Vamos partir do ponto em que você já adicionou os discos em sua maquina e não os formatou. Os meus discos aqui utilizados, serão hd´s SCSI.

Inicialmente vamos ver a estrutura dos nossos dispositivos.

# cat /proc/partitions
major minor #blocks name

8 0 83886080 sda
8 1 200781   sda1
8 2 20482875 sda2
8 3 2096482  sda3
8 4 61103227 sda4
8 16 1048576 sdb
8 32 1048576 sdc
8 48 1048576 sdd
8 64 1048576 sde

# ls /dev/sd*
/dev/sda /dev/sda2 /dev/sda4 /dev/sdc /dev/sde
/dev/sda1 /dev/sda3 /dev/sdb /dev/sdd

Como adicionamos discos SCSI, devemos ver eles através /dev/sd*. sda é nosso disco principal, onde está instalado o sistema operacional, e sda1 a sd4 são suas particões. Podemos perceber que existem quatro discos sem formatações (sdb, sdc, sdd, sde), através da saida ‘cat /proc/partitions’ nos mostra que esses discos ainda não tem partições. É permitido criar no mínimo um partição para cada disco, mais podemos ter mais de uma partição e usa-lás como diferentes discos ASM.

Vamos criar uma partição em cada disco bruto (sdb, sdc, sdd, sde) através do fdisk.


# /sbin/fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

/* Nesse momento o fdisk está esperando uma ação para ser realizada no disco ‘/dev/sdb’. Usamos a opção “n” do fdisk para iniciar a criação de uma nova partição. */
Command (m for help): n

/* Aqui é questinado se a nova partição será primaria ou extendida. Vamos usar uma partição primária. */
Command action
e extended
p primary partition (1-4)
p

/* Nesse momento é definido o número da partição, usaremos a 1. As outras opções de cilindro, e o tamanho máximo da partição é definido como default. Somente pressione a tecla “ENTER”. */
Partition number (1-4): 1
First cylinder (1-130, default 1):
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-130, default 130):
Using default value 130

/* Confirmamos as alterações no disco com a opção “w”. */
Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Agora se observamos novamente a saida do comando ‘cat /proc/partitions’ a partição /dev/sdb1 está criada no disco /dev/sdb.

# cat /proc/partitions
major minor #blocks name

8 0 83886080 sda
8 1 200781 sda1
8 2 20482875 sda2
8 3 2096482 sda3
8 4 61103227 sda4
8 16 1048576 sdb
8 17 1044193 sdb1
8 32 1048576 sdc
8 48 1048576 sdd
8 64 1048576 sde

Repita esse procedimento acima para os outros 3 discos, da mesma maneira. No final você terá um ambiente como esse.

# cat /proc/partitions
major minor #blocks name

8 0 83886080 sda
8 1 200781 sda1
8 2 20482875 sda2
8 3 2096482 sda3
8 4 61103227 sda4
8 16 1048576 sdb
8 17 1044193 sdb1
8 32 1048576 sdc
8 33 1044193 sdc1
8 48 1048576 sdd
8 49 1044193 sdd1
8 64 1048576 sde
8 65 1044193 sde1

Coloque essas linhas no arquivo /etc/udev/rules.d/60-raw.rules. Isso é necessário para iniciar os raw devices no momento da inicialização do SO, e a permissão de acesso aos discos para o usuário “oracle”


ACTION=="add", KERNEL=="sdb1", RUN+="/bin/raw /dev/raw/raw1 %N"
ACTION=="add", KERNEL=="sdc1", RUN+="/bin/raw /dev/raw/raw2 %N"
ACTION=="add", KERNEL=="sdd1", RUN+="/bin/raw /dev/raw/raw3 %N"
ACTION=="add", KERNEL=="sde1", RUN+="/bin/raw /dev/raw/raw4 %N"

# permissão dos discos para o usuário oracle do sistema operacional.
ACTION==”add”, KERNEL==”raw*”, OWNER==”oracle”, GROUP==”oinstall”, MODE==”0660″

Feito isso, execute os seguintes comandos para ligar as partições a os dispositivos brutos.

# /bin/raw /dev/raw/raw1 /dev/sdb1
# /bin/raw /dev/raw/raw2 /dev/sdc1
# /bin/raw /dev/raw/raw3 /dev/sdd1
# /bin/raw /dev/raw/raw4 /dev/sde1

Agora iniciamos o udev, para definir as mudanças.

# /sbin/start_udev
Starting udev:
[ OK ]

E pronto, agora temos 4 dispositivos brutos instalados no nosso sistema.

# raw -qa
/dev/raw/raw1: bound to major 8, minor 17
/dev/raw/raw2: bound to major 8, minor 33
/dev/raw/raw3: bound to major 8, minor 49
/dev/raw/raw4: bound to major 8, minor 65

No momento da criação de um group disk, olha os raw devices ai.

Quanto tempo vai demorar o backup?

agosto 10th, 2010 por Flávio Soares

Uma das formas para descobrir quanto tempo ainda falta para terminar o backup realizado com RMAN, é consultando a view v$session_longops.

Essa view mostra as vários operações que estão executando por mais de 6 segundos no banco de dados Oracle.

Veja os passos abaixos:

Primeiro vamos relacionar o processo servidor com o channel do RMAN, através do comando SET COMMAND ID


RMAN> run {
2> allocate channel t1 type disk;
3> set command id to ‘rman’;
4> backup datafile 1;
5> release channel t1;
6> }

Agora, basta executar a query, vendo o resultado.

SYS@orcl> SELECT sid, serial#, sofar, totalwork,
2      round(sofar/totalwork*100,2) "% Complete"
3 FROM v$session_longops
4 WHERE opname LIKE 'RMAN:%'
5 AND opname NOT LIKE 'RMAN: aggregate%'
6 AND totalwork != 0;

SID        SERIAL#      SOFAR    TOTALWORK   % Complete
---------- ---------- ---------- ---------- ----------
139          17        13951       62720         22.24

SYS@orcl> /

SID        SERIAL#      SOFAR    TOTALWORK   % Complete
---------- ---------- ---------- ---------- ----------
139          17        24831       62720         39.59

SYS@orcl> /

SID        SERIAL#      SOFAR    TOTALWORK   % Complete
---------- ---------- ---------- ---------- ----------
139          17        62591       62720         99.79

Sql Prompt

julho 19th, 2010 por Flávio Soares

Uma dica que já é bem antiga, mais que para muitos pode ser algo novo … o SQLPROMPT.

Se você já se cansou de ver nosso amigo de guerra SQL*Plus o prompt “SQL >”, realmente faltou você conhecer o comando sqlprompt.

Ele simplesmente tem a ação de mudar o nome de exibição do prompt SQL*Plus.
Não acredita? Pois bem, experimente …


SQL> set sqlprompt “Novo Prompt> ”
Novo Prompt> prompt funcionou
funcionou
Novo Prompt> set sqlp “Mudando prompt> ”
Mudando prompt>

E isso não é tudo, você pode usar com variables, veja meu exemplo


SQL> set sqlp '[ &MeuNome@SQL*Plus ] ‘
Enter value for meunome: Flavio
[ Flavio@SQL*Plus ]

E se você pensa que acabou, errado! Que tal usar sqlprompt com variáveis de runtime do SQL*Plus para ajudar a identificar a instância em que você está conectado.


SQL> set sqlprompt "_user'@'_connect_identifier> "
SYS@orcl> set sqlprompt "_user' '_privilege> "
SYS AS SYSDBA>

E se eu sair do SQL*Plus?


SYS AS SYSDBA> exit

[oracle@orcl ~]$ sqlplus / as sysdba

SQL>

Sim, você perde suas alterações feitas. Mas a grande notícia é que se editar o arquivo glogin.sql localizado em:

$ORACLE_HOME/sqlplus/admin/glogin.sql

Você poderá deixar permanente suas alterações do SQL*Plus.

Colunas virtuais

julho 4th, 2010 por Flávio Soares

Coluna Virtual é uma nova feature do Oracle 11g que permite utilizar colunas puramente como expressões que são armazenadas no dicionário de dados. Desde a versão 8i temos ao nosso alcance a possibilidade de armazenar expressões utilizando function-based indexes.

Agora com a versão 11g temos a possibilidade de armazenar expressões diretamente em tabelas através das colunas virtuais.

Nesse artigo vou demonstrar usos básicos das colunas virtuais, algumas considerações sobre performance e suas limitações.

Como criar um coluna virtual?

SYNTAX

column_name [datatype] [GENERATED ALWAYS] AS (expression) [VIRTUAL]

SQL> create table triangulo
2 (
3 base number,
4 altura number,
5 area number generated always as ((base * altura) / 2) virtual
6 )
7 /

Table created.

A tabela criada, é responsável por armazenas bases e alturas de triângulos, onde a coluna area armazenará a expressão matemática ((base x altura) / 2).

Agora vamos inserir um triângulo com base 5 e altura 6. Observe que não inserimos nada na coluna area, ela será gerada automaticamente. O primeiro insert gerará um erro propositalmente, aonde estou querendo mostrar que não podemos adicionar colunas virtual na syntax insert (e update).


SQL> insert into triangulo (base, altura, area) values (5, 6, 15);
insert into triangulo (base, altura, area) values (5, 6, 15)
*
ERROR at line 1:
ORA-54013: INSERT operation disallowed on virtual columns

Insert correto:

SQL> insert into triangulo (base, altura) values (5, 6);

1 row created.

SQL> select * from triangulo;

BASE        ALTURA          AREA
---------- ---------- ----------
     5         6        15

A expressão pode ser visualizada pela coluna DATA_DEFAULT na view [DBA|ALL|USER]_TAB_COLUMNS.


SQL> select column_name, data_default
2 from dba_tab_columns
3 where table_name = 'TRIANGULO';

COLUMN_NAME     DATA_DEFAULT
-------------- -----------------------
BASE
ALTURA
AREA            "BASE"*"ALTURA"/2

SQL> select column_name, data_type
2 from dba_tab_cols
3 where table_name = 'TRIANGULO'
4 and virtual_column = 'YES';

COLUMN_NAME          DATA_TYPE
-------------------- --------------------------------
AREA                  NUMBER

Algumas considerações sobre performance

Embora muito já se falou sobre o famoso “SELECT * FROM”, com colunas virtuais irá punir ainda mais a performance para quem emprega essa prática. Imagine que para cada linha que trouxer do seu SELECT, existam 3 colunas virtuais, isso tudo deverá ser gerado em runtime, ou seja, somente no momento da execução do SELECT que os dados serão “criados”, implicações significativas de desempenho são possíveis nesses casos. É extremamente importante, qualquer aplicação que utilize das colunas virtuais que use explicitamente as colunas que deseja utilizar, evitando assim desperdicio de processamento.

Limitações

  • Colunas virtuais não podem ser baseadas em outras colunas virtuais.
  • Elas não suportadas em index-organized, external, object, tabelas temporarias ou cluster.
  • Indexes nas colunas virtuais, são iguais a function-based indexes.
  • Eles podem ser usadas na clausula WHERE em updates e deletes, mais não podem ser manipuladas como DML.
  • Índices inutilizáveis.

    abril 18th, 2010 por Flávio Soares

    Se um índice torna-se inutilizável, ele sempre deverá ser reparado antes que possa ser usado. Diferentemente de um objeto PL/SQL por exemplo, pois a primeira vez que é acesso o objeto é recompilado automaticamente pelo Oracle.

    Mais quando um índice se torna inutilizável?

    Se os rowids da tabela forem modificados por qualquer razão, então os índices será marcado como inutilizável, isso por que o rowid é o ponteiro físico para a localização da linha a qual a chave de índice se refere.

    Como identificar índices inutilizáveis?

    Índices inutilizáveis são detectados utilizando a seguinte consulta.

    SQL> select index_name, table_name from dba_indexes where status = 'UNUSABLE';

    Versões anteriores do Oracle, quando se executava uma instrução SQL que tentasse usar um índice inutilizável, retornaria um erro e a instrução toda falharia. Com o 10g em diante, a instrução que vou utilizar um índice inutilizável, o banco reverterá para um plano de execução que não necessite de índice, mas isso pode causar uma grande queda de desempenho. Esse comportamento pode ser trocado mudando o parâmetro de inicialização SKIP_UNUSABLE_INDEXES para false, que por padrão é true.

    SQL> alter system set skip_unusable_indexes=false;

    Como reparar índices inutilizáveis?

    Índices são reparados utilizando o comando ALTER INDEX … REBUILD. Isso gerará um novo índice com ponteiros das rowid atualizados para a chave de índice.

    Os mais importantes parâmetros do comando rebuild são TABLESPACE, NOLOGGING, ONLINE.

    TABLESPACE : Se você deseja construir seu índice em um tablespace diferente da sua tabela.

    NOLOGGING: Diz ao Oracle a não gerar redo para a operação de construção de índice. Isso torna a reconstrução muito mais rápida, mais assim o índice não sobreviverá a um dado causado que requeira o uso do restore e recovery. Se for utilizar essa opção, lembre-se sempre de gerar um backup do tablespace, assim você está seguro a falhas.

    ONLINE: A geração de índices exige um certo esforço do banco de dados, principalmente se a tabela for muito grande. Por padrão o processo de reconstrução bloqueia todo DML que vier de encontro a tabela no momento da reconstrução, isso pode ser evitado usando ONLINE no comando.

    Reparando Índices

    Vamos a um exemplo prático, onde será necessário reconstruir um índice.


    SQL> create table t
    2 (
    3     id number
    4 ) tablespace users;
    5 /

    Table created.

    SQL> create index id_idx on t(id);

    Index created.

    Vamos confirmar que o índice está valido.


    SQL> select index_name, status from user_indexes;

    INDEX_NAME                   STATUS
    ------------------------------ --------
    ID_IDX                            VALID

    Agora, vamos movimentar a tabela T do tablespace USERS para o tablespace TB_TESTE. Assim os índices vão perder todas as suas referências, conseqüentemente se tornará inutilizável pelo plano de execução Oracle.


    SQL> alter table t move tablespace tb_teste;

    Table altered.

    Se verificarmos o status do índice, ele estará com o status alterado para UNUSABLE.


    SQL> select index_name, status from user_indexes;

    INDEX_NAME                        STATUS
    ------------------------------ --------
    IDX_ID                         UNUSABLE

    Para tornar o indice válido, apenas devemos reconstruir os ponteiros das rowids executando o comando rebuild.


    SQL> alter index idx_id rebuild online nologging;

    Index altered.

    SQL> select index_name, status from user_indexes;

    INDEX_NAME                   STATUS
    ------------------------------ --------
    ID_IDX                            VALID

    Após o comando REBUILD, o índice já estará pronto para ser utilizado novamente.

    Mais novo OCA.

    março 24th, 2010 por Flávio Soares

    Agora sim, sou Oracle Certified Associate : )

    Mais um objeto concluído, tirar a OCA com 21 anos. Semana passada sai da minha pacata cidade e fui para São Paulo prestar a prova. Foi excelente experiência que tive, pretendo ainda esse ano voltar e tentar a OCP.

    Para quem está se preparando, digo que vale a pena o esforço. É muito bom ver o resultado PASS no monitor da cabine de certificação : )

    Históricos de comandos no SQLPlus

    fevereiro 7th, 2010 por Flávio Soares

    Infelizmente, para quem usa SQLPlus nos Linux sabe como é frustrante não ter o histórico dos comandos executados assim como é possível fazer no shell do Linux.

    O RLWRAP é um ferramenta free e muito simples de utilizar que permite vizualizar os históricos executados através do SQLPlus.

    Passo 1: Instale o RLWRAP através do YUM, ou abaixe através do site http://utopia.knoware.nl/~hlub/uck/rlwrap/.

    $ yum install rlwrap

    Passo 2: Mude seu .bashrc e adicione as seguintes linhas.

    alias sqlplus='rlwrap sqlplus'
    alias rman='rlwrap rman'

    Pronto, após o logout do seu usuário os históricos do SQLPlus estarão habilitados.

    Nos testes que realizei ele funcionou legal, somente em alguns casos a ação “CONTROL + C”, para cancelar alguma solicitação não funcionou, mas mesmo assim eu o recomendo. Essa é uma dica simples que garanto que vai ser de grande ajuda para muitos.

    Conflitos de bloqueios

    dezembro 8th, 2009 por Flávio Soares

    O Oracle como outros bancos de dados, deve gerenciar múltiplos usuários acessando a mesma data simultaneamente, garantindo o controle de concorrência do banco de dados.

    Conflitos de bloqueios (lock conflicts) ocorrem quase que frequentemente durante as operações das transações, mais geralmente são quase todas resolvidos pelo próprio mecanismo de fila da Oracle. Para entender melhor o lock conflicts observe a tabela abaixo.

    TRANSAÇÃO 1 TEMPO TRANSAÇÃO 2
    UPDATE PRODUTO
    SET valor = 30
    WHERE id_produto = 1;

    1 row updated.

    08:00 UPDATE PRODUTO
    SET valor = 50
    WHERE id_produto = 2;

    1 row updated.

    UPDATE produto SET valor = 52
    WHERE id_produto = 2;

    Nenhuma linha atualizada no momento, pois a transação 1 entra em lock conflict com a transação 2.

    08:15 Transação continua normal, utilizando selects, inserts, updates e até mesmo deletes na mesma ou em outras tabelas.
    Sessão ainda aguardando 08:20 Transação continua normal, utilizando selects, inserts, updates e até mesmo deletes na mesma ou em outras tabelas.
    1 row updated.

    Liberado o lock, a sessão continua normalmente.

    08:25 commit;

    A tabela mostra a atividade, de duas transações. Observe no horário das 08:15 que a transação 1 não conseguiu fazer o update, pois a transação 2 estava como lock na linha. Somente as 08:25, quando o commit da transação 2 é feito, o lock é liberado que a transação 1 consegui realizar a operação.

    Como em nenhum ambiente o cenário é perfeito (como o do meu quadro apresentado), o usuário não vai ficar esperando cinco minutos um simples update de outra transação ser liberado para ele trabalhar, ele vai imediatamente contatar você que o banco está lendo, não esta funcionando, e por ai vai…

    Evitando os lock conflicts.

    Obviamente para se ter um pouco de prevenção dos conflitos, é necessário assegurar que nenhuma transação execute por longos períodos de tempo sem um commit (DDL, DCL). A cada mudança, assim que necessário, pedir para o LGWR trabalhar (processo de commit), fazendo a gravação dos dados persistente nos arquivos de Redo e consequentemente nos Datafiles

    Detectando os lock conflicts.

    É realmente fácil detectar usuário que sofrem bloqueios e os que fazem o bloqueio. Para isso criaremos um ambiente para o melhor entendimento do conceito. O script abaixo cria o usuário usr1 e o usuário usr2.

    SQL> create user usr1
    2 profile default
    3 identified by oracle
    4 quota unlimited on users
    5 account unlock;

    Usuário criado.

    SQL> create user usr2
    2 profile default
    3 identified by oracle
    4 quota unlimited on users
    5 account unlock;

    Usuário criado.

    SQL> grant create table, connect to usr1, usr2;

    Concessão bem-sucedida.

    Agora com o usuário usr1 criamos a tabela de produto e disparamos dois insert.

    SQL> create table produto
    2 (
    3 id_produto number primary key,
    4 valor number(10,2)
    5 )
    6 /

    Tabela criada.

    SQL> insert into produto values (&id, &valor);
    Informe o valor para id: 1
    Informe o valor para valor: 50

    1 linha criada.

    SQL> /
    Informe o valor para id: 2
    Informe o valor para valor: 5

    1 linha criada.

    SQL> commit;

    Commit concluído.

    Ainda como o usuário usr1, vamos dar a permissão de update para o usuário usr2, assim garantimos que o usr2 poderá acessar a tabela de usr1.

    SQL> grant update on produto to usr2;

    Concessão bem-sucedida.

    Agora sim, nosso ambiente está pronto para detectar os locks. Com o usuário usr1 faça um update atualizando a coluna valor para 35 onde o id_produto é igual a 1.

    SQL> update produto set valor = 35
    2 where id_produto = 1;

    1 linha atualizada.

    Em outro terminal, com o usuário usr2 também atualizamos a coluna valor onde o id_produto é igual a 1, observe o lock entrando em ação.

    SQL> update usr1.produto set valor = 36
    2 where id_produto = 1;
    _

    A sessão do usr2 fica aguardando algum commit da transação do usr1. Para conseguir detectar sessões que estão bloqueando outras sessões, basta executar o select baixo.

    SQL> select username from v$session
    2 where sid in (
    3 select blocking_session from v$session
    4 )
    5 /

    USERNAME
    ------------------------------
    USR1

    Verificando usuários que estão aguardando commit de outra sessão.

    SQL> select sid, username, blocking_session
    2 from v$session
    3 where blocking_session is not null;

    SID USERNAME BLOCKING_SESSION
    ----- ------------ ----------------
    136  USR2        141

    Usuários que estão com o lock, e usuário que estão aguardando a outra transação.


    SQL> select sid, username, blocking_session
    2 from v$session where blocking_session is not null
    3 UNION ALL
    4 select A.sid, A.username, A.blocking_session
    5 from v$session A, v$session B
    6 where A.sid = B.blocking_session;

    SID USERNAME BLOCKING_SESSION
    ---- ---------- ----------------
    136  USR2                 141
    141  USR1

    Resolvendo lock conflicts.

    Somente é possível resolver conflitos de bloqueios através de duas maneiras:

    1) Emitir um commit na sessão que está bloqueando
    2) Terminar a sessão que está bloqueando.

    A melhor maneira de resolver é contatar o usuário que está segurando o lock e pedir para liberar, afim de poder completar a transação. Como nem sempre está opção é possível, existe uma maneira mais rápida radical, que seria finalizar a sessão pelo modo kill do Oracle.

    ALTER SYSTEM KILL SESSION ‘SID, SERIAL#’ IMMEDIATE;


    SQL> select sid, serial#
    2 from v$session where username = 'USR1';

    SID          SERIAL#
    ---------- ----------
    141            46

    SQL> alter system kill session '141, 46' immediate;

    Sistema alterado.

    Depois de alguns segundos, se voltarmos para o terminal do usuário usr2, pode observar que o update antes que estava aguardando terminar o lock do usuário usr1, é atualizada.


    1 linha atualizada.

    SQL>

    Por fim, aqui está outras views com informações de lock disponível no Oracle:

    V$ENQUEUE_LOCK
    V$EVENT_NAME
    V$LOCK
    V$_LOCKV
    $LOCKED_OBJECT
    V$LOCKS_WITH_COLLISIONS
    V$LOCK_ACTIVITY
    V$LOCK_ELEMENT

    Uma dica do nosso amigo Jorge, para ambientes RAC, as views como V$SESSION e V$LOCK mostram somente os dados atuais da instância em que o usuário está conectado. Para resolver esse problemas existem as views :

    GV$ENQUEUE_LOCK
    GV$LOCK_ELEMENT
    GV$LOCKS_WITH_COLLISIONS
    GV$LOCKED_OBJECT
    GV$LOCK
    GV$EVENT_NAME
    GV$LOCK_ACTIVITY

    Que mostram os dados independente, do cluster que ele estará.

    Obrigado pela dica Jorge.

    Index na prática

    outubro 23rd, 2009 por Flávio Soares

    Existe no Oracle diversos mecanismos para otimizar a performance do banco de dados, uma dessas formas, é a possibilidade de criar index em tabelas.

    Antes de fazermos nosso exemplo prático, deixarei algumas diretrizes que a Oracle recomenda em relação a index. Devemos sempre prestar atenção nessas recomendações afim de realizar um trabalho eficiente. Fique atento com a criação deles, se algum index for mal construído, poderá até afetar a performance do banco dados.

    Veja algumas:

    Quando criar index

  • Quando a coluna contém um grande range de valores.
  • A coluna contém vários valores null.
  • A tabela deve ser grande.
  • Quando a maioria das consultas, espera recuperar menos do que 2% a 4% das linhas da tabela.
  • Frequentemente, a(s) coluna(s) é usada em WHERE cláusula ou em condições de join.
  • Quando não criar index

  • Quando a coluna não for usada em condições na consulta.
  • A tabela é atualizada frequentemente.
  • Quando tabela for pequena.
  • A maioria das consultas expera recuperar mais do que 2% a 4% das linhas da tabela.
  • Vamos iniciar nosso teste criando um ambiente para ele, execute o seguinte comando para criar a tabela T com os registros da tabela all_objects.

    SQL> create table t as select object_name name, object_id id from all_objects;

    Tabela criada.

    Vamos dar um pouco mais de carga nessa tabela.

    SQL> insert into t select * from t;

    49871 linhas criadas.

    SQL> select count(*) from t;

    COUNT(*)
    ----------
    99742

    Agora com a tabela criada, vamos executar a seguinte query observando seu tempo:

    SQL> set timing on
    SQL> select name
    2 from t
    3 where upper(substr(name,5,2)) in
    4 ('AA','V$','AR','OE','HS','AO','KO','NT','ZO','GQ',
    5 'XH','JO','BS','ML','AL','WW','PX','XX','IU','AO',
    6 'CZ','JX','CQ','CW','CE','CR','CT','CY','CU','CI',
    7 'MT','AH','LV','EG','BB','MO','MY','BQ','AE','AT')
    8 /

    ...

    NAME
    ------------------------------
    INVENTORY_LIST_TYP
    REJECTION_T
    SUBCATEGORY_REF_LIST_TYP
    SUBCATEGORY_REF_LIST_NESTEDTAB
    CAL_MONTH_SALES_MV

    2018 linhas selecionadas.

    Decorrido: 00:00:04.32

    O select acima, executou a consulta em 4 segundos e 32 milisegundos. Agora vamos executar a query novamente, mais antes disso, criaremos um index baseado em função na tabela T, e veremos novamente o tempo gasto para retornar a mesma consulta.


    SQL> create index nameidxt
    2 on T
    3 (upper(substr(name, 5,2)));

    Índice criado.

    Agora esvaziamos o BUFFER_CACHE, para que o Oracle não apresse a consulta já executada anteriormente.

    SQL> alter system flush buffer_cache;

    Sistema alterado.

    Executamos a mesma consulta, mais agora com o index criado na tabela, compare o tempo gasto da primeira vez que executamos, com a segunda vez.

    SQL> select name
    2 from t
    3 where upper(substr(name,5,2)) in
    4 ('AA','V$','AR','OE','HS','AO','KO','NT','ZO','GQ',
    5 'XH','JO','BS','ML','AL','WW','PX','XX','IU','AO',
    6 'CZ','JX','CQ','CW','CE','CR','CT','CY','CU','CI',
    7 'MT','AH','LV','EG','BB','MO','MY','BQ','AE','AT')
    8 /

    ...

    NAME
    ------------------------------
    INVENTORY_LIST_TYP
    REJECTION_T
    SUBCATEGORY_REF_LIST_TYP
    SUBCATEGORY_REF_LIST_NESTEDTAB
    CAL_MONTH_SALES_MV

    2018 linhas selecionadas.

    Decorrido: 00:00:00.70

    Se compararmos o tempo gasto nas duas execuções veremos uma diminuição enorme no tempo, de 4.32 para 0.70, ou seja a mesma query executada apenas com a inclusão de um index baseado em função, nos permite estar em um nível maior de performance.

    Apesar do index fornecer para esse tipo de situação, e para outros, notórios tempos de melhorias, é importante saber aonde criar cada um deles, observar atentamente as recomendações citadas acima, para que possa atender a sua real necessidade.