Показаны сообщения с ярлыком Cache. Показать все сообщения
Показаны сообщения с ярлыком Cache. Показать все сообщения

Updatable cache and transactional order

Recently, I received a very interesting question about TimesTen cache. The customer would like to use TimesTen as a front office database and decided to use AWT cache group for that. The application creates a lot of transactions per second and basically changes the client balance. The question is "How will TimesTen transfer changes to Oracle database?". I think its a very good question, because I know customers who would like to use TimesTen for decreasing the load on production Oracle DB and in this case the transactional order is quite important.
Let's create a simple test. Oracle DB:
SQL> show user
USER is "ORATT"
SQL> create table awttab ( a number not null primary key, b varchar2(100) );

Table created.

SQL> select count(*) from awttab;

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

SQL> grant select, insert, update, delete on awttab to cacheadmin;

Grant succeeded.

SQL>
TimesTen:
[oracle@nodett1 ~]$ ttisql "DSN=ds_test;UID=cacheadmin;PWD=oracle"

Copyright (c) 1996-2011, Oracle.  All rights reserved.
Type ? or "help" for help, type "exit" to quit ttIsql.

connect "DSN=ds_test;UID=cacheadmin;PWD=oracle";
Connection successful: DSN=ds_test;UID=cacheadmin;DataStore=/u01/app/oracle/product/datastore/ds_test;DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;DRIVER=/u01/app/oracle/product/11.2.2.4/TimesTen/tt11224/lib/libtten.so;LogDir=/u01/app/oracle/product/datastore/ds_test/log;PermSize=1024;TempSize=128;TypeMode=0;PLSQL_TIMEOUT=1000;CacheGridEnable=0;OracleNetServiceName=orcl;
(Default setting AutoCommit=1)
Command> call ttCacheUidPwdSet('cacheadmin','oracle');
Command> call ttCacheStart;
Command> CREATE ASYNCHRONOUS WRITETHROUGH CACHE GROUP awtcache
       > FROM oratt.awttab ( a NUMBER NOT NULL PRIMARY KEY,
       >                     b VARCHAR2(100));
Command> call ttRepStart;
Command>

[oracle@nodett1 ~]$ ttisql "DSN=ds_test;UID=oratt;PWD=oracle"

Copyright (c) 1996-2011, Oracle.  All rights reserved.
Type ? or "help" for help, type "exit" to quit ttIsql.

connect "DSN=ds_test;UID=oratt;PWD=oracle";
Connection successful: DSN=ds_test;UID=oratt;DataStore=/u01/app/oracle/product/datastore/ds_test;DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;DRIVER=/u01/app/oracle/product/11.2.2.4/TimesTen/tt11224/lib/libtten.so;LogDir=/u01/app/oracle/product/datastore/ds_test/log;PermSize=1024;TempSize=128;TypeMode=0;PLSQL_TIMEOUT=1000;CacheGridEnable=0;OracleNetServiceName=orcl;
(Default setting AutoCommit=1)
Command> select * from awttab;
0 rows found.
Command>
We created an AWT cache group on a table awttab. Insert a row into the table.
Command> insert into awttab values (1,'test');
1 row inserted.
Command> select * from awttab;
< 1, test >
1 row found.
Command>
Transaction was committed automatically (autocommit on). Check the record inside Oracle DB.
SQL> select * from awttab;

         A B
---------- ------------------
         1 test

SQL>
Let's update this row 50 times by using the following code. Before that I turn on the 10046 event on cacheadmin Oracle DB user.
Command> begin
       >   for i in 1 ..50 loop
       >      update awttab set b = 'test'||i where a=1;
       >      commit;
       >   end loop;
       > end;
       > /

PL/SQL procedure successfully completed.

Command> select * from awttab;
< 1, test50 >
1 row found.
Command>
As you can see, I updated the same row 50 times and used the following order:
update1 -> commit 
update2 -> commit
...
update50 -> commit
Basically, this type of transactions (each DML statement ends by commit) is very often used in OLTP systems and can cause the performance problems (see log_file_sync wait event), so let's have a look on tracing files. We can see information about each statement there:
 
...
PARSING IN CURSOR #6328852 len=67 dep=1 uid=90 oct=6 lid=90 tim=1355414103869999 hv=317616249 ad='48b693a0' sqlid='dk6k6dc9fww3t'
UPDATE "ORATT"."AWTTAB" SET "B" = :"SYS_B_0" WHERE "A" = :"SYS_B_1"
END OF STMT
PARSE #6328852:c=0,e=307,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,plh=1356545142,tim=1355414103869995
BINDS #6328852:
 Bind#0
  oacdty=01 mxl=32(06) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0100 frm=01 csi=178 siz=32 off=0
  kxsbbbfp=4b176ea0  bln=32  avl=06  flg=09
  value="test1"
 Bind#1
  oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=4b176e80  bln=22  avl=02  flg=09
  value=1
EXEC #6328852:c=1000,e=494,p=0,cr=1,cu=1,mis=0,r=1,dep=1,og=1,plh=1356545142,tim=1355414103870584
STAT #6328852 id=1 cnt=0 pid=0 pos=1 obj=0 op='UPDATE  AWTTAB (cr=1 pr=0 pw=0 time=265 us)'
STAT #6328852 id=2 cnt=1 pid=1 pos=1 obj=75894 op='INDEX UNIQUE SCAN SYS_C0011095 (cr=1 pr=0 pw=0 time=71 us cost=1 size=65 card=1)'
CLOSE #6328852:c=0,e=6,dep=1,type=0,tim=1355414103870744
===================
PARSING IN CURSOR #6328852 len=67 dep=1 uid=90 oct=6 lid=90 tim=1355414103870949 hv=317616249 ad='48b693a0' sqlid='dk6k6dc9fww3t'
UPDATE "ORATT"."AWTTAB" SET "B" = :"SYS_B_0" WHERE "A" = :"SYS_B_1"
END OF STMT
PARSE #6328852:c=0,e=124,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,plh=1356545142,tim=1355414103870944
BINDS #6328852:
 Bind#0
  oacdty=01 mxl=32(06) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0100 frm=01 csi=178 siz=32 off=0
  kxsbbbfp=48b7fb28  bln=32  avl=06  flg=09
  value="test2"
 Bind#1
  oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=48b7fb10  bln=22  avl=02  flg=09
  value=1
EXEC #6328852:c=1000,e=240,p=0,cr=1,cu=1,mis=0,r=1,dep=1,og=1,plh=1356545142,tim=1355414103871275
STAT #6328852 id=1 cnt=0 pid=0 pos=1 obj=0 op='UPDATE  AWTTAB (cr=1 pr=0 pw=0 time=50 us)'
STAT #6328852 id=2 cnt=1 pid=1 pos=1 obj=75894 op='INDEX UNIQUE SCAN SYS_C0011095 (cr=1 pr=0 pw=0 time=11 us cost=1 size=65 card=1)'
CLOSE #6328852:c=0,e=6,dep=1,type=0,tim=1355414103871426
...
But there is no information about commit. And only after the last statement we see
 
PARSING IN CURSOR #6328852 len=67 dep=1 uid=90 oct=6 lid=90 tim=1355414103907559 hv=317616249 ad='48b693a0' sqlid='dk6k6dc9fww3t'
UPDATE "ORATT"."AWTTAB" SET "B" = :"SYS_B_0" WHERE "A" = :"SYS_B_1"
END OF STMT
PARSE #6328852:c=0,e=100,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,plh=1356545142,tim=1355414103907555
BINDS #6328852:
 Bind#0
  oacdty=01 mxl=32(07) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0100 frm=01 csi=178 siz=32 off=0
  kxsbbbfp=48b5f340  bln=32  avl=07  flg=09
  value="test100"
 Bind#1
  oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=48b5f330  bln=22  avl=02  flg=09
  value=1
EXEC #6328852:c=0,e=181,p=0,cr=1,cu=1,mis=0,r=1,dep=1,og=1,plh=1356545142,tim=1355414103907813
STAT #6328852 id=1 cnt=0 pid=0 pos=1 obj=0 op='UPDATE  AWTTAB (cr=1 pr=0 pw=0 time=38 us)'
STAT #6328852 id=2 cnt=1 pid=1 pos=1 obj=75894 op='INDEX UNIQUE SCAN SYS_C0011095 (cr=1 pr=0 pw=0 time=7 us cost=1 size=65 card=1)'
CLOSE #6328852:c=0,e=5,dep=1,type=0,tim=13554141039080
...
XCTEND rlbk=0, rd_only=0, tim=1355414103908136
As you can see, TimesTen tries to combine transactions in transactional order and applies them in efficient way. For example instead of execute transactions in the original order like this:
update1 -> commit 
update2 -> commit
...
update50 -> commit
TimesTen executed them like the following:
update1 -> update2 ... -> update50 -> commit
This method provides an opportunity to decrease load on Oracle Database. So, TimesTen provides not only the opportunity to achieve SLA and very low response time, additionally you can decrease the load on your production Oracle DB.

Доступ ко всем данным из TimesTen (Passthrough=1)

Недавно ко мне обратился заказчик с задачей:
существуют "огромные партиционированные таблицы (терабайты данных), к части из которых идет частое обращение. Возможно ли чтобы из ТТ были доступны определенные партиции, а остальные брались из оракла по тому же подключению ТТ".

Попробуем решить данную задачу.

Предположим у насть есть партицированная таблица в Oracle Database.

[oracle@tt1 cache_article]$ sqlplus oratt/oracle@orcl

SQL*Plus: Release 11.1.0.7.0 - Production on Tue May 24 09:22:15 2011

Copyright (c) 1982, 2008, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create table accounts (
  2  Id number,
  3  Name varchar2 (50),
  4  Surname varchar2(50),
  5  constraint accounts_pk primary key (id)
  6      using index (create unique index account_pk_idx on accounts(id))
  7  )
  8  partition by range (id) (
  9  partition part1 values less than (1000),
 10  partition part2 values less than (2000),
 11  partition part3 values less than (3000)
 12  );

Table created.

SQL> begin
2  for i in 1 .. 100 loop
3    insert into accounts values (i, 'Pit'||i, 'Jounes'||i);
4  end loop;
5 end;
6/
  
PL/SQL procedure successfully completed.

SQL> begin
2  for i in 1001 .. 1100 loop
3    insert into accounts values (i, 'Pit'||i, 'Jounes'||i);
4  end loop;
5 end;
6/
  
PL/SQL procedure successfully completed.

SQL> begin
2  for i in 2001 .. 2100 loop
3    insert into accounts values (i, 'Pit'||i, 'Jounes'||i);
4  end loop;
5 end;
6/
  
PL/SQL procedure successfully completed.

SQL> select count(*) from accounts;

  COUNT(*)
----------
       300

SQL> grant select on accounts to cacheadmin;

Grant succeeded.


Предположим, что частое обращение происходит к первой партиции, т.е. будем кэшировать первую партицию (ограничим ее условием where в определении кэш группы).

Command> CREATE READONLY CACHE GROUP read_cg
       >   AUTOREFRESH INTERVAL 5 SECONDS
       > FROM oratt.accounts (   Id number not null primary key,
       >                       Name varchar2 (50),
       >                    Surname varchar2(50)
       > ) where id <= 999;
Command> load cache group read_cg commit every 265 rows;
100 cache instances affected.


Но как получить данные из других партиций?
Для этого будем использовать параметр Passthrough.
Если данный параметр имеет значение 1, то каждый запрос, выполненный к несуществующим обектам в TimesTen будет перенаправлен в Oracle Database для исполнения.

Следовательно, создаем представление в Oracle Database, которое будет содержать данные из остальных партиций.

SQL> create view accounts_all as select * from accounts where id > 999;

View created.

SQL> grant select on accounts_all to cacheadmin;

Grant succeeded.


После чего можем иметь доступ ко всей информации через одно подключение (но, к сожалению, через разные таблицы).

Command> connect "DSN=db_cache1;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache1;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache1;DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;PermSize=32;TempSize=50;TypeMode=0;PLSQL_TIMEOUT=1000;CacheGridEnable=0;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> select count(*) from accounts;
< 100 >
1 row found.
Command> select count(*) from accounts_all;
 2206: Table ORATT.ACCOUNTS_ALL not found
The command failed.
Command> set autocommit 0;
Command> call ttOptSetFlag('PassThrough', 1);
Command> select count(*) from accounts_all;
< 200 >
1 row found.
Command>
Command> set showplan 1;
Command> select count(*) from accounts;

Query Optimizer Plan:

  STEP:                1
  LEVEL:               1
  OPERATION:           TblLkSerialScan
  TBLNAME:             ACCOUNTS
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         

< 100 >
1 row found.
Command>  select count(*) from accounts_all;

Query Optimizer Plan:

  STEP:                1
  LEVEL:               1
  OPERATION:           Oracle PassThrough
  TBLNAME:             
  IXNAME:              
  INDEXED CONDITION:   
  NOT INDEXED:         

< 200 >
1 row found.
Command>


Следовательно, получили доступ ко всей таблице Accounts через одно подключение в Oracle TimesTen.

In-Memory Database Cache Grid

Ну вот я наконец то добрался до рассмотрения появившегося в TimesTen 11g функционала - In-Memory Database Cache Grid.
Начнем с настройки. В документации процесс создания Cache grid на нескольких машинах описан, на мой взгляд, не досточно четко, поэтому я и решил начать с его конфигурации.

Используемое окружение (три виртуальные машины):

OEL 5.3 (x86) - Oracle Database EE 11.2.0.2.0 – 192.168.2.131 (hostname - db)
OEL 5.3 (x86) - Oracle TimesTen 11.2.1.7.0 (32 bit Linux/x86) – 192.168.2.132 (hostname – tt1)
OEL 5.3 (x86) - Oracle TimesTen 11.2.1.7.0 (32 bit Linux/x86) – 192.168.2.133 (hostname – tt2)

Предварительная настройка для кэш грида, в общем, очень похожа на настройку TimesTen для работы с Oracle Database (об этом можно почитать здесь).


Tech: Настройка In-Memory Database Cache 11g

Давно я что-то не писал не чего технического (да и на русском :) ), вот и решил это исправить. Так как литературы по TimesTen мало, то я решил обновить статью Jonathan Gennick -а о кэшировании. В данном посте рассматривается возможность кэширования данных из Oracle Database в Oracle TimesTen.

Примечание: в данной статье не будет рассматриваться функциональность In-Memory Database Cache Grid, т.е. будет рассмотрена возможность создания только локальных кэш групп.

Используемое окружение (две виртуальные машины):
OEL 5.3 (x86) - Oracle Database EE 11.2.0.2.0 (Linux/x86), ip - 192.168.2.131 (hostname - db)
OEL 5.3 (x86) - Oracle TimesTen 11.2.1.7.0 (Linux/x86), ip - 192.168.2.132 (hostname - tt1)