Baran İpek Oracle and Java

September 13, 2011

RESTful Web Services

Filed under: java — baranipek @ 7:04 pm

I could not write  blog entry for a long time because of intense pace of work and master but I wanna publish one of my article (that I wrote for my lesson ) is about with Restful Web Service.  I hope that is useful for you and gives idea. You can reach via link below.
Click Here

October 3, 2010

Vulnerability in OC4J

Filed under: java — baranipek @ 6:52 pm

I encountered one of oc4j vulnerability and want to share this experience. Container_tabs.jsp  is  reachable and vulnerable for Cross Site Scripting that is not part of my ear file  when you type url like http://domain/webapp/jsp/container_tabs.jsp. This jsp is located under home/j2ee/applications/webapp/jsp folder  and this page could be exploited by attackers to execute arbitrary scripting code. The solution is enable securty_mod if it isn’t  or you need to remove this page. The last option is waiting for a patch from Oracle but as we know Oracle tend to support Weblogic instead Oc4j.

For further reading

http://hungred.com/web-development/solutions-crosssite-scripting-xss-attack/

February 12, 2010

Multithread Url Call with Java

Filed under: java — baranipek @ 9:34 am

Assume that you want to make sure  your web application’s concurrency as a curious developer:). We can call url with get method through a simple java class. We will test two cases. First test will show us 20 concurent user call url at the same time.However,we will use Executors classes for concurrency call and  Thread classes for consecutive call. Thanks to this test,you can monitor Heap usage and memory allocated in the application server.

————–Test-1
import java.io.IOException;
import java.util.Calendar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MultiproccesingIndependent {
ExecutorService executor = Executors.newFixedThreadPool(1);

public void start() throws IOException {
int i=0;

while (!executor.isShutdown() && i<20)
executor.submit(new MyThread(i++));
}

public void shutdown() throws InterruptedException {
executor.shutdown();
executor.awaitTermination(30, TimeUnit.SECONDS);
executor.shutdownNow();
}

public static void main(String argv[]) throws Exception {
new MultiproccesingIndependent().start();
}
}

class MyThread implements Runnable {
private int i;
MyThread(int i) {
this.i = i;
}

public void run() {

Calendar cal = Calendar.getInstance();

MultiProcessing urlReader = new MultiProcessing();
try {

urlReader
.callAdress(url);

} catch (IOException e) {

e.printStackTrace();
}

}
}

——-Test-2

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.URL;

import java.net.URLConnection;

public class MultiProcessing {

static void threadMessage() {

String threadName = Thread.currentThread().getName();

System.out.print(threadName);

}

private static class MessageLoop implements Runnable {

public MessageLoop() {

}

public void run() {

synchronized (MessageLoop.class) {

try {

threadMessage();

MultiProcessing urlReader = new MultiProcessing();

urlReader.callAdress(“your url“);

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

public void callAdress(String urlEnd) throws IOException

{

URL url = new URL(urlEnd);

URLConnection conn = null;

try {

conn = url.openConnection();

} catch (IOException e) {

e.printStackTrace();

}

BufferedReader in = new BufferedReader(new InputStreamReader(conn

.getInputStream()));

String line;

while ((line = in.readLine()) != null) {

System.out.println(line);

}

}

public static void main(String args[]) throws InterruptedException {

for (int i = 0; i < 30; i++)

{

MessageLoop mLopp = new MessageLoop();

new Thread(mLopp).start();

}

}

For further reading

http://java.sun.com/docs/books/tutorial/essential/concurrency/

January 20, 2010

How to run an application on a specific port in OC4j

Filed under: java — baranipek @ 12:06 pm

On the whole, lots of applications are running on the same application server. In order to distinguish applications from each other, you must have different URL’s on the same port. Adding a new port is another and also smart way to do this. I use OC4j version of 10.1.2.3 as a application server.

When it comes to adding port in OC4j, Firstly, you must create an instance that runs at the port then you add port in turn by clicking http server, Administration and server properties tab. I added 6000 port as you see below in order to use it later.

After that, you must create virtual host will use port which you added before.

         Now we have port and virtual host and we have to relate port with instance. Under  Advanced server properties, you must edit httpd.conf file and add this commands  below.

    NameVirtualHost *:6000

    Listen 6000

    <VirtualHost _default_:6000>

        ServerName xxxxx.com.tr

        SSLWallet file:D:\OraHome_1\Apache\Apache\conf\ssl.wlt\default

        SSLEngine on

        CustomLog D:\OraHome_1\Apache\Apache\logs\smth

        Port 6000

    </VirtualHost>

This step will  provide us to relate port with your instance. You must edit mod_ocf4.conf file and  add this commands  below

<VirtualHost *:6000>

        Oc4jMount / instancename

        Oc4jMount /* instancename

        ServerName  serverip 

    </VirtualHost>

For more reading

http://download-west.oracle.com/docs/cd/A97329_03/core.902/a92171/config.htm

January 13, 2010

A short comparison between HIBERNATE and JDBC

Filed under: java — baranipek @ 2:56 pm

Nowadays, ORM is a hot topic in java world. You have many options if you decide to use ORM in your Project  but hibernate is the most popular one.When we look into advantages  of hibernate, Caching and connection pooling is  not maintained manually in hibernate. It is done by hand-coding in JDBC.  JDBC supports only sql but hibernate is independant from database and provides query language HQL that is similar to  native sql. Hibernate also supports native sql. With JDBC you must handle result set and convert it to java object but hibernate  reduces code lines by maintaining object-table mapping and return java object to application.As many approaches,hibernate has also disadvantages beside its advantages.  In case of simple database that never changes ,hibernate increase complexity. For complex data ,conversion  reduces performance. As you know, learning hibernate is overhead for developers. So you must estimate software costs well . The choice depends on Project requirements,the skill of development team.

August 18, 2009

Increase the memory of OC4J standalone server

Filed under: java — baranipek @ 7:45 pm

 If your  jsp or servlet pages  have any problems and you see  “java.lang.OutOfError” in your log files then you probably increase your JVM’s heap size. But before then  I strongly recommend you to revise your code before increasing heapsize. Maybe you don’t use connection pooling or  you create object in infinite loop J (I hope you don’t do that).

If you use oc4j as a application server you will  edit opmn.xml  file .Adding parts of the xml file are highlighted below.  I increase 64 that is default to 512 M.  Once you change the file, execute the command below to request OPMN to reload the configuration file into memory:

>$ORACLE_HOME/opmn/bin/opmnctl reload and then and then start the OC4J instance.

 

<process-type id=”myinstance” module-id=”OC4J“>

-<module-data>

- <category id=”start-parameters“>

  <data id=”java-options” value=”-server -Xrs -Djava.security.policy=D:\Hukuk10gAS\j2ee\hukuk\config\java2.policy -Djava.awt.headless=true -XX:PermSize=128m -XX:MaxPermSize=128m –Xms512m –Xmx512m” />

  <data id=”oc4j-options” value=”-properties” />

  </category>

- <category id=”stop-parameters“>

  <data id=”java-options” value=”-Djava.security.policy=D:\Hukuk10gAS\j2ee\hukuk\config\java2.policy -Djava.awt.headless=true />

  </category>

  </module-data>

  <start timeout=”900” retry=”2” />

  <stop timeout=”120” />

  <restart timeout=”720” retry=”2” />

  <port id=”ajp” range=”12501-12600” />

  <port id=”rmi” range=”12401-12500” />

  <port id=”jms” range=”12601-12700” />

  <process-set id=”default_island” numprocs=”1” />

  </process-type>

 

 

For more reading

http://download.oracle.com/docs/cd/B25221_04/core.1013/b15976/opmnxml.htm

http://www.deakin.edu.au/its/dba/oracle-doco/9.0.4.1/9.0.4_doc_library/integrate.904/b12121/perf.htm

October 5, 2008

Java Collections

Filed under: java — baranipek @ 6:20 pm

This is my first blog entry on java technologies. My friend asked me why I don’t publish articles on Java. So i ama little excited. Well, Today we glance at Collection on java. A collection in data structure terms, is a group of elements.It includes Sets and Lists. It also includes Maps which don’t implement Collection. Collection is the interface implemented by classes such as Arraylists,TreeSet and HashSet implement. It defines to methods to them all. Collection classes live in java.util package. I want to give ArrayList and LinkList Class example that implements List interface

public class Data {
protected int  myArray [];
public int size ;
public Data()
{
myArray = new int [50];
}
public Data (int n)
{
myArray = new int[50];
size =n;
}
protected void finalize() {
System.out.println(“cleaned” + size);

}
}

import java.util.*;

public class ArrayListExample
{

public static void main(String[] args) {
ArrayList l = new ArrayList();
int sizeOfL ;
for (int i = 0; i<5; i++)
{
l.add(new Data(i));
}
sizeOfL = l.size();
for (int i = 0; i <sizeOfL; i++) {
int size =((Data) l.get(i)).size;
System.out.println(“elements 1…” + size);
}

l.add(0, new Data(6)); // 6,0,1,2,3,4
l.add(2, new Data(17)); // 6,0,17,1,2,3,4
sizeOfL = l.size();

for (int i = 0; i <sizeOfL; i++) {
int size =((Data) l.get(i)).size;
System.out.println(“elements 2….” + size);
}
l.remove(3); //6,0,17,2,3,4
List sub = l.subList(1, 3); // 0,17
}

}

A LinkedList is similar to an ArrayList in that it is ordered by index position. If you want to have random access of the list
Arraylist offers quick access than LinkList but this comes at slower operations for adding and removing in the middle of the
list.
Vector is synchronized whereas ArrayList is not.ArrayList and Vector class both implement the List interface. Both classes are implemented using dynamically resizable arrays, providing fast random access and fast traversal when you want programs to run in multithreading environment then use concept of vector because it is synchronized. But ArrayList is not synchronized so, avoid use of it in a multithreading environment.Arraylist has no default size but vector has size of ten. We can see using capacity()method.

import java.util.*;
public class Demo1 {
public static void main(String[] args) {
//creating vector
Vector v= new Vector();
v.add(“baran”);
v.add(“ipek”);
//creating enumeration interface
Enumeration E=v.elements();
System.out.println(“Element are : “);
while(E.hasMoreElements())
{
System.out.println(E.nextElement()+”\t”);
}
//Returns the current capacity of this vector.
int i=v.capacity();
System.out.println(“Capacity of the vector is: “+i);
}

}

February 16, 2008

PL/SQL EXCEPTIONS

Filed under: Oracle — baranipek @ 4:15 pm

Evde yaptıgım ufak bir exceptions örneğini anlatmak istedim. Birazda giriş sevyesinde fonksiyonlar ve ref cursor hakkında bilgi vermiş olacağım. Çok basit bir işlem yapan fonksiyon 3 kolondan oluşan tabloma ID verip diger bilgileri alan fonksiyon yazdım cursor döndürcem sonuç olarak. O zaman hemen fonksiyonu yazalım. Eger exception alırsam 1 parametresini yollicam.

CREATE OR REPLACE FUNCTION test
(
iid IN NUMBER,
ostatu OUT NUMBER
) RETURN SYS_REFCURSOR AS
TYPE v_cursor IS REF CURSOR;
p_cursor v_cursor;
verrormsg VARCHAR2(4000);

l_row VARCHAR2(200) := ”;
BEGIN
l_row := ‘select * from deneme where ID = :iID’;

OPEN p_cursor FOR l_row
USING iid;

EXCEPTION
WHEN OTHERS THEN
ostatu := 1;
verrormsg := substr(SQLERRM, 1, 3000);
INSERT INTO log_data VALUES (iid, verrormsg, SYSDATE);
COMMIT;
RETURN p_cursor;

END;

Hemen ardından test ediyim bakalım data getiriyormu ?

DECLARE
refcursor SYS_REFCURSOR;
vid NUMBER;
vname VARCHAR2(100);
vn_statu NUMBER;
vil NUMBER;
BEGIN

refcursor := test(104022008230216, ostatu => vn_statu);

LOOP
FETCH refcursor
INTO vid, vname;
EXIT WHEN refcursor%NOTFOUND;

dbms_output.put_line(vid || ‘ | ‘ || vname);

END LOOP;
CLOSE refcursor;
END;

Getiriyor valla denedim gördüm. Sonra ne zorum varsa gidip select çektiğim tabloyu drop ettim. Dedimki o zaman log_data tablosu yapıyım da hatayı göriyim sanki bilmiyomuşum gibi:) Exception kısmından gelebilecek tüm exceptionlar için when others then kullandım. Sonra yine test ettim .

DECLARE
refcursor SYS_REFCURSOR;

vn_statu NUMBER;

BEGIN

refcursor := test(104022008230216, ostatu => vn_statu);

dbms_output.put_line(vn_statu);
CLOSE refcursor;
END;

OUT parametrem olan 1 gördüm ve merat edip gidip log tabloma baktım. Evet table or view doesn’t exist diyor allah allah ne oldu acaba:) Basit bir örnek göstermek istedim tabi bu arada yaptıgım eksikler de var hızlı yapıyım derken. Mesela paketin içine yazmalıydım fonksiyonu,dynamic sql ‘e gerek varmı ? vb.. ama dediğim gibi örneklendirmek için basit bir örnek göstermek istedim.

September 21, 2007

PL/SQL performans

Filed under: Oracle — baranipek @ 8:20 am

Using Bind or Not

SGA’nın bölümlerinden biri olan shared pool data dictionary cache ve library cache olarak iki bölümden oluşur. Library cache yazdığımız ve kullandığımız en son sql ve pl/sql leri (procedure ve function vb..) saklar yani LRU(last recent used) algoritması doğrultusunda çalıştırır. Örneğin yazdığımız bir function bir kullancı tarafından kullanılmak istendiğinde kullanıcı bunu shared pool dan alır ve function zaten memory de olduğu için performansdan kazanmış olurum. O zaman library cache alanından haberdar olmak bir database developer için bize büyük fayda sağlayacaktır.

Library cache’in shared sql area sında yeni bir sql gelirse yeni alan oluşturulup sql için parse tree ve execution bilgileri oluşturulur. Tüm alanlar dolduğunda daha once bahsettiğimiz LRU algoritması ile alanlar sql lere dağıtılır. SQL’in çalışması için dört evresinden (parsing,optimization,row-source generation,execution) birincisi parsing işlemidir. Parsing işleminde sql’in doğru yazılıp yazılmadığı,sql deki objelerin olup olmaması ,daha önce sql’in kullanılıp kullanılmadığı gibi daha birçok işlem kontrol edilir ki bu da en maliyetli kısım olarak karşımıza çıkıyor. O zaman bir developer olarak performans için elimizden geldiği kadar parsing işlemini minimum sevyede tutmaya çalışacağız. O zaman amacımız ‘one parse-execute many’ olacaktır.

Daha öncede bahsettiğimiz gibi developer sql ve pl/sql yazdıktan sonra Oracle shared pool’a gidip daha önceden parse ve optimized işlemi yapılmış diye bakar. Eğer bulursa tekrar kullanır ve bu sistem için en performanslı yoldur . Eğer bulamazsa yukarda bahsettiğimiz dört aşamadan geçer. İşte bu noktada bind variable yardımımıza koşacaktır. Tek kullanıcılı sistemde performans farkı kullanıp kullanmama arasında daha az olacktır ama analizler yine bind kullanımı destekleyecektir.

Select * from emp where empno=123;

Selct * from emp where empno=:empno;

Mesela yukardaki ilk sorguda 123 nolu employee getirdim. Sonra bunu 234,345 vb gibi değiştirdiğim zaman her seferinde sorgumu baştan parse etmiş olacağım. Bind variable kullandığım ikinci sorguda ise sorgu bir kez compile edilip query planıyla birlikte library cache saklanır. Daha sonra istenildiği zaman parse edilmeden kullanılabilinir. Şimdi daha önceden bahsettiğimiz tkprof ile örneklerimizi analiz edelim. Birincisinde bind variable kullanıp ikincisinde kullanmayacağım. Alter system flush shared_pool ile testimin sağlıklı sonuç vermesi için shared pool’u sıfırlayacağım.

set timing on
set serveroutput on

alter session set max_dump_file_size=unlimited;
ALTER session SET timed_statistics = true;
alter session set STATISTICS_LEVEL = ALL ;

alter system flush shared_pool;
alter system flush buffer_cache;

alter session set tracefile_identifier = bind ;
ALTER SESSION SET EVENTS ’10046 TRACE NAME CONTEXT FOREVER, LEVEL 12′;

declare
TYPE rc IS REF CURSOR;
l_rc rc;
l_dummy all_objects.object_name%TYPE;
l_start NUMBER DEFAULT dbms_utility.get_time;
BEGIN
FOR i IN 1 .. 1000 LOOP
OPEN l_rc FOR ‘select object_name
from all_objects
where object_id = :x ‘ USING i;
FETCH l_rc INTO l_dummy;
CLOSE l_rc;
END LOOP;
dbms_output.put_line(round((dbms_utility.get_time – l_start) / 100,
2) || ‘seconds…’);
END;
/

ALTER SESSION SET EVENTS ’10046 TRACE NAME CONTEXT OFF’;

1.48seconds…

set timing on
set serveroutput on

alter session set max_dump_file_size=unlimited;
ALTER session SET timed_statistics = true;
alter session set STATISTICS_LEVEL = ALL ;

alter system flush shared_pool;
alter system flush buffer_cache;

alter session set tracefile_identifier = nobind1 ;
ALTER SESSION SET EVENTS ’10046 TRACE NAME CONTEXT FOREVER, LEVEL 12′;

declare
TYPE rc IS REF CURSOR;
l_rc rc;
l_dummy all_objects.object_name%TYPE;
l_start NUMBER DEFAULT dbms_utility.get_time;
BEGIN
FOR i IN 1 .. 1000 LOOP
OPEN l_rc FOR ‘select object_name
from all_objects
where object_id = ‘ || i;
FETCH l_rc INTO l_dummy;
CLOSE l_rc;
END LOOP;
dbms_output.put_line(round((dbms_utility.get_time – l_start) / 100,
2) || ‘seconds…’);
END;
/

ALTER SESSION SET EVENTS ’10046 TRACE NAME CONTEXT OFF’;

31.02seconds…

İki sorgu arasında zaman farkı anlamak için başta ve sonda dbms_utility.get_time ile zamanı alıp kıyasladığımda bind kullanmadan yaklaşık 30 katı kadar sure fazla harcamış gözüküyorum. İlk trace dosyamın boyutu 57kb ikne ikinci trace dosyam 3mb civarında. O zaman trace dosyalarımızın farkının nerden geldiğine bir bakalım.

call count cpu elapsed disk query current rows
Parse 1063 0.02 0.02 0 0 0 0
Execute 1092 0.17 0.23 0 0 0 0
Fetch 1301 0.08 0.93 171 6790 0 1203
total 3456 0.27 1.19 171 6790 0 1203

Misses in library cache during parse: 7

call count cpu elapsed disk query current rows
Parse 2100 29.07 29.73 0 6 0 0
Execute 2296 0.34 0.31 0 0 0 0
Fetch 2612 0.32 2.10 200 10549 0 3646
total 7008 29.73 32.15 200 10555 0 3646

Misses in library cache during parse: 1019

Yukardaki analizleri kıyasladığımda ikinci trace’imde parse işlemin maliyeti görüldüğü gibi cpu değerine de yansıdı. Fazladan parsing,cpu kullanımı,response time performansımın düşmesine neden oldu.

Bind

select object_name
from all_objects
where object_id = :x

call count cpu elapsed disk query current rows
Parse 1000 0.02 0.01 0 0 0 0
Execute 1000 0.15 0.19 0 0 0 0
Fetch 1000 0.05 0.19 49 6315 0 953
total 3000 0.22 0.40 49 6315 0 953

Nobind

select object_name
from all_objects

where object_id = 1

call count cpu elapsed disk query current rows
Parse 1 0.07 0.07 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.00 0.02 2 5 0 1
total 3 0.07 0.09 2 5 0 1

………………………………………..
………………………………………..
……………………………………….

select object_name
from all_objects

where object_id = 999

call count cpu elapsed disk query current rows
Parse 1 0.07 0.07 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.00 0.02 3 8 0 1
total 3 0.07 0.09 3 8 0 1

Birinci trace dosyamda yukardaki sorgu için bir defa plan oluşturuluken ikinci sorgumda x değerinin 1000’e kadar her değeri için ayrı parse etti ve plan oluşturdu ve bu ikinci trace dosyamın büyük boyutlara ulaşmasına neden oldu. Bind variable’nın parse sayısını azaltması cpu kazanımın yanında çoklu kullanıcılarda library cachedeki latch sayısını da azaltacağı için sistem daha hızlı çalışacaktır. Share sql alanında bir anda tek oturum hard parse edeceğinden birçok kullanıcının hard parse yapması bekleme yaratacaktır. Bu da yine performans kaybına yol açar.

Bind variable performansın yanında veritabanı güvenliği açısından da önemlidir. Sql injection sql üzerinden veritabanına sızma olarak adlandırılır. Bu bir paket çağırma,verileri göstermek olabilir. Sql injection olması için sql’in dynamic sql olması gerekir ve gelecek parametrelere gore runtime sırasında oluşur ve bu da güvenlik açısından bir açık olarak karşımıza çıkabilir. İşte bu noktada bind variable kullanımı yardımımıza yetişiyor.

IF you use dynamic sql
AND
you use string concatenation
THEN
you are subject to sql injection
END IF

Yukarda ifade ettiğimiz gibi concatenation kullanımı sql injection için uygun zemin hazırlayacaktır. Şimdi sql injection yönetmi ile ilgili bir örnek yapıp bind kullanımın yararlarını görelim. Önce bir tablo yaratacağız sonra sonra bir fonksiyon yardımıyla banka hesabına sızmaya çalışağız.

create table my_top_secrets (
PK_SECRET VARCHAR2(30) PRIMARY KEY,
BANK_ACCOUNT VARCHAR2(30),
AMOUNT NUMBER(10)
);
insert into my_top_secrets values(’1′, ‘Malta Bank – 123456′, 123000000);
insert into my_top_secrets values(’2′, ‘Isviçre Bank – 7890′, 4567000000);
commit;

create or replace function get_bankaccount(p_secret varchar2) return varchar2 is
TYPE rc IS REF CURSOR;
l_rc rc;
l_dummy varchar2(64) := ‘Fail’;
BEGIN
OPEN l_rc FOR ‘select BANK_ACCOUNT
from my_top_secrets
where PK_SECRET = ‘|| p_secret;
FETCH l_rc INTO l_dummy;
CLOSE l_rc;
return l_dummy ;
END;

Tabloyu yaratıp satırları ekledik sonra bize banka hesaplarını getirmesini istedik .

set serveroutput on
declare
l_dummy1 varchar2(64) := ‘-1′;
l_dummy2 varchar2(64);
begin
l_dummy2 := get_bankaccount(l_dummy1);
dbms_output.put_line(l_dummy2);
end;
/
Fail
PL/SQL procedure successfully completed.

Dedikten sonra beklendiği üzere fail mesajını aldık

declare
l_dummy1 varchar2(64) := ‘-1′ || ‘ or 1=1′;
l_dummy2 varchar2(64);
begin
l_dummy2 := get_bankaccount(l_dummy1);
dbms_output.put_line(l_dummy2);
end;
/

Malta Bank – 123456

Yukarıda kırmızıyla eklenen kısımla banka hesabımızın içine sızılmış oldu. Halbuki fonksiyonu yazarken bu durumu düşünmemiştik. O zaman bu gibi durumlara karşı önlem almak için fonksiyonda bind kullanıp tekrar sızmaya çalışalım.

create or replace function get_bankaccount (p_secret varchar2) return varchar2 is
TYPE rc IS REF CURSOR;
l_rc rc;
l_dummy varchar2(64) := ‘Fail’;
BEGIN
OPEN l_rc FOR ‘select BANK_ACCOUNT
from my_top_secrets
where PK_SECRET = :x ‘ USING p_secret;
FETCH l_rc INTO l_dummy;
CLOSE l_rc;
return l_dummy ;
END;
/
declare
l_dummy1 varchar2(64) := ‘-1′|| ‘or 1=1′;
l_dummy2 varchar2(64);
begin
l_dummy2 := get_bankaccount(l_dummy1);
dbms_output.put_line(l_dummy2);
end;
/

Fail

Bind kullanımından sonra bilgilerimize ulaşılamadı. Zaten bind kullanımın performasını yukarıda ıspatlamıştık. O zaman dynamic sql ifadelerde veya java da bind kullanamadığımız durumlar hariç(tablo isimleri,colon isimleri vb) her zaman bind kullanımı performans ve güvenliğimiz açısından yararlı olacaktır.

Cursor

PL/SQL içinde SQL yazdığımız zaman Oracle sqller için özel bir alan tahsis eder. Bu alan yazdığımız sqllerden ve getirdiği kayıtlardan oluşur. Cursor bu alana isim verebilmemizi ve içerdiği kayıtarı işlememizi sağlayan pl/sql mekanizmasıdır ya da başka bir deyişle veritabanımdaki tabloların içindeki pointer olarak söylenebilinir. İki çeşit cursor tanımlayabiliriz.

Kapalı İmleçler(İmplicit Cursor): Yazılan her sql komutları için Oracle tarafından otomatik olarak açılan imleçlerdir. Yazılan her kapalı imleç için SQL%NOTFOUND, SQL%ROWCOUNT, SQL%FOUND, SQL%NOTFOUND özellikleri açıktır.Cursor declare etmeye gerek yoktur .

SELECT SUM (salary) INTO department_total
FROM employee
WHERE department_number = 10;

Yukardaki ifader için Oracle implicit cursor otomatik olarak yaratacaktır. Eğer ifade birden fazla satır getitirse exception yaratacaktır. İkinci satırı getirmem için TOO_MANY_ROWS exception’ a ihtiyacım olacaktır .

Açık İmleçler(Explicit Cursor):Programcı tarafından belirli bir işi yapabilmek için açılan imleçlerdir..Cursordaki birden çok satıra tek tek erişme, processde olan satırı işlemek gibi işlemleri programcıya sunan cursor çeşididir. Parametre alabilir.

declare
cursor c1 is select ename, job, sal from emp;
v_ename emp.ename%type;
v_job emp.job%type;
v_sal emp.sal%type;
begin
open c1;
loop
fetch c1 into v_ename, v_job, v_sal;
exit when c1%notfound;
dbms_output.put_line(v_ename||’ ‘|v_job||’ ‘||v_sal);
end loop;
end;
/

Yukarda gördüğümüz önce cursorı declare ettik sonra open ile açtık ve bir döngü içerisinde daha once kolonla aynı type da kolon değişkenlere fetch ettik. Yukarıda gördüğümüz gibi cursorun açılması,fetch edilmesi ve kapanması herşeyi programcı yapıyor fakat implicit cursorda Oracle bu işlemleri otomatik yapar. Şimdi implicit ve explicit cursorları kıyaslayalım ve hangisi kullanacağımıza karar verelim. İlk önce performansları kıyaslayalım.

İmplicit cursor

create or replace procedure implicit_interpreted( p_times in number )
as
l_dummy dual.dummy%type;
l_start number default dbms_utility.get_time;
begin
for i in 1 .. p_times
loop
select * into l_dummy from dual;
end loop;
dbms_output.put_line( (dbms_utility.get_time-l_start) || ‘ hsecs…’ );
end;
/

Explicit cursor

create or replace procedure explicit_interpreted( p_times in number )
as
cursor c is select * from dual;
l_dummy dual.dummy%type;
l_start number default dbms_utility.get_time;
begin
for i in 1 .. p_times
loop
open c;
fetch c into l_dummy;
if ( c%notfound ) then
raise no_data_found;
end if;

fetch c into l_dummy;
if ( c%found ) then
raise too_many_rows;
end if;

close c;
end loop;
dbms_output.put_line( (dbms_utility.get_time-l_start) || ‘ hsecs…’ );
end;
/

exec explicit_interpreted( 50000 );

PL/SQL procedure successfully completed.

Elapsed: 00:00:26.51

call count cpu elapsed disk query current rows
Parse 31 0.00 0.00 0 0 0 0
Execute 50035 1.14 1.13 0 0 0 0
Fetch 100113 1.41 1.89 78 150264 0 50093
total 150179 2.55 3.02 78 150264 0 50093

exec implicit_interpreted( 50000 );

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.48

call count cpu elapsed disk query current rows
——- —— ——– ———- ———- ———- ———- ———-
Parse 31 0.00 0.00 0 0 0 0
Execute 50035 1.00 1.05 0 0 0 0
Fetch 50113 1.43 2.27 76 150267 0 50093
——- —— ——– ———- ———- ———- ———- ———-
total 100179 2.43 3.33 76 150267 0 50093

Parse ve execute aynı değerlere sahip çıktı. Elapsed süreleri için explicit cursor’ın daha fazla çıktı. Cpu kullanımı explicit de daha fazla olduğunu gördük. İmplicit cursor daha performanslı olduğunu burda ıspatladı Ayrıca select into yazmanın open,fetch,close yazmaya gore kadar kolay olduğu örneğimizden de görebiliriz. Sadece sql ile yapabileceğimiz sorguları sql ile yapmalı ve bunu pl/sql bırakmalıyız. Bu bize performans kaybı olarak dönecektir. Daha öncede bahsetdiğimiz gibi kolay yazılıp okunan kompleks olmayan kodlar herzaman bizim için daha avantajlı olacaktır.

İmplicit

for x in ( select * from t )
loop
….
end loop

Explicit
Cursor is select * from t;
open c;
loop
fetch c into x;
exit when c%notfound
….
end loop;
close c;

Yukardaki aynı işlevi yapan iki farklı cursora baktığım zaman daha öncede bahsettiğimiz yazım kolaylığı ortaya çıkıyor. Explicit cursorda bazen nerde cursor’ın açılacağını nerde kapanacağını ya da nıasl yazılacağını unutabilirsiniz. Kısacası kompleks sorgulardan uzak durmaktan yana olacağız. İmplicit ile ilgili ilk örneğimizde birden fazla satır getirmemiz gerektiğinde TOO_MANY_ROWS exceptionu kullanmamız gerekir demiştik. Aşağıdaki örnekleri inceleyip bu durumu tekrar gözden geçirelim.

Explicit cursor

declare
l_dname dept.dname%type;
l_deptno dept.deptno%type;
l_ename emp.ename%type;

cursor c1
is
select deptno, dname
from dept
order by deptno;

cursor c2( p_deptno in number )
is
select ename
from emp
where deptno = p_deptno
and sal = (select max(sal)
from emp
where deptno = p_deptno);
begin
open c1;
loop
fetch c1 into l_deptno, l_dname;
exit when c1%notfound;
open c2(l_deptno);
fetch c2 into l_ename;
close c2;
dbms_output.put_line
( l_deptno || ‘, ‘ || l_dname || ‘, ‘ || l_ename );
end loop;
close c1;
end;
/

İmplicit cursor

declare
l_ename emp.ename%type;
begin
for x in (select deptno, dname from dept order by deptno)
loop
begin
select ename into l_ename
from emp
where deptno = x.deptno
and sal = (select max(sal)
from emp
where deptno = x.deptno)
and rownum = 1;
exception when no_data_found
then
l_ename := ‘(none)’;
end;
dbms_output.put_line
( x.deptno || ‘, ‘ || x.dname || ‘, ‘ || l_ename );
end loop;
end;
/

Yukarda yazdığımız implicit cursor bu sefer birden fazla satır getirme ihtimaline karşı hata vermesine karşın rownum=1 ile tek tek getirmesini ve no_data_found ile boş satır getirmesi durumunda ne yapması gerktiğini söyledik ve böylece implicit cursor ile ilgili birden fazla satır getirirken TOO_MANY_ROWS exception kullanmamız gerektiği ve explicit cursor’ın bize daha fazla kontrol etme imkanı sunduğu gibi ifadeleri yıkmış olduk. İmplicit cursor’ın performansını ve kullanım kolaylığını ıspatladıktan sonra artık geriye bize implicit cursor kullanmak düşüyor.

Using the BULK COLLECT Clause

Yukarıda gördüğümz gibi sql ifadelerimiz çalışırken pl/sql engine ve sql engine sürekli birbirleriyle satır transferi halindedirler. Bulk Binding iki engine arasında satırları transfer ederken collections(dizi veya liste) halinde gönderme olanağı sağlar. Bu da performansı artıracaktır.

Bulk Collect bulk binding ‘in select sorguları için kullandığı sentaksıdır.Bulk Collect bütün satırları tek seferde resul set olarak almamızı sağlar. Satırda istediğimiz kolonu değişkene atarak istediğimiz işlemi yapmamızı sağlar ve bunu çok hızlı bir şekilde yapar. SELECT INTO, FETCH INTO, and RETURNING INTO clauseları yardımıyla kullanabiliriz.Şimdi bir tablo yaratıp all_objects kayıtlarını alalım ve birkaç kez defa insert edelim.

create table t_all_objects as select * from all_objects;

insert into t_all_objects select * from t_all_objects;

insert into t_all_objects select * from t_all_objects;

Bulk

SQL> declare
2 cursor c1 is select object_name from t_all_objects;
3 type c1_type is table of c1%rowtype;
4 rec1 c1_type;
5 begin
6 open c1;
7
8 fetch c1 bulk collect into rec1;
9
10
11 end;
12 /

call count cpu elapsed disk query current rows
Parse 28 0.01 0.02 2 2 0 0
Execute 30 0.02 0.02 0 0 0 0
Fetch 84 0.97 2.47 1433 1609 0 110660
total 142 1.00 2.52 1435 1611 0 110660

Nobulk

declare
cursor c1 is select object_name from t_all_objects;
rec1 c1%rowtype;
begin
open c1;
loop
fetch c1 into rec1;
exit when c1%notfound;
null;
end loop;
end;

call count cpu elapsed disk query current rows
Parse 14 0.01 0.01 1 1 0 0
Execute 15 0.02 0.01 0 0 0 0
Fetch 98346 1.50 2.16 1259 98405 0 98338
total 98375 1.53 2.19 1260 98406 0 98338

Yukarıda görüldüğü gibi ilk örneğimde fetch ederken bulk collect kullandım. Sql ve pl/sql engine arasındaki row satır interaction azaldı, fetch sayım azaldı ve daha az cpu kullanımı sağlamış oldum.

Düşünelim Bakalım

Filed under: Zeka Soruları — baranipek @ 8:18 am

Aslında zekanın bir iki soruyla ölçülmeyeceğini düşünsemde(çok yönlü bir kavram) yinede bazı begendiğim sorular oluyor onları paylaşmak istedim.Emrehan Halıcının zeka soruları kitabından yazıcam yavşa yavaş bir-iki soruyla başlayalım sonra yazarım cevapları:)

1-)İki arkadaş bir oyun oynuyor. 10 tane şişeden sırayla 1 ya da 2 şişe alma şansınız var. Sıranızda sizde iken diğerine şişeleri alıp diğerine şişe bırakmayan oyunu kazanıyor. Oyuna sizin başladığınızı düşünürseniz oyunu kazanmak için nasıl bir yol izlersiniz.

2-)İki arkadaş atlarını yarştırmak istiyorlar ama farklı olarak yarışmayı sonuncu kazanacaktır.İkiside başlangıç çizigisine geliyor ama yarışmayı sonuncu kazanacağı için başlamak istemiyorlar. Bu yarışmayı nasıl gerçekleştiririz o zaman?

3-)100 tane kartım var ve üstlerinde yazılar var. İlk kartı açtım ve üstünde “bu kartların yalnızca bir tanesi yalan söylüyor ” yazıyor ikinciyi açıyorum “bu kartların yalnızca iki tanesi yalan söylüyor” yazıyor ve yazılar açtığım kartın sırası olarak artarak gidiyor .Peki kaçıncı kart doğru söylüyor.

Devamı gelecek:)

Next Page »

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.