5 Ocak 2011 Çarşamba

Oracle Sequence Nedir? Bilinmeyen Detaylarıyla

Merhabalar,

Sequence

Oracle'da "sequence" yani Türkçe'si ile sıra, dizi veya sekans olarak adlandırdığımız yapılar bulunmaktadır. Bu yapıların amacı belirlediğimiz bir başlangıç noktasından başlayarak, artı veya eksi yönde sayı arttırmaktır. Dizi, sürekli olarak kullanımdan doğan numara artış veya azalışlarını temin etmektedir. Diziler genelde sanal bir anahtar olarak kullanılır ve bir çeşit sıralama yapabilmemiz için faydalıdır. Tıpkı constraint'ler gibi, sequence'lar da data dictionary içerisinde bulunur ve kayıtları tutulur. Herhangi bir alan tahsis etmezler, yalnızca sayalar ve sıra tutarlar. Dizilere bir üst veya alt limit vererek, nerede biteceğini ve yeniden başlaması gerektiğini de söyleyebiliyoruz.

Sequence Yaratmak ve Düşürmek

Sekans veya diziler CREATE SEQUENCE ifadesi ile yaratılırlar. İlk önce bu ifade ile birlikte nelerin varsayılan olarak gösterildiğini ve hangi parametreleri değiştirebileceğimize bakalım.

SQL> CREATE SEQUENCE ogan_seq START WITH 1001;

Sequence created.

START WITH: Sekansın hangi numara veya sayı ile başlayacağını ifade eder. Azalan sekanslar için MAXVALUE değeri -1 iken artış gösterecek olan sekanslar için varsayılan MINVALUE değeri 1'dir.

INCREMENT BY: Arka arkaya devamı gelecek ve üretilecek olan numara veya sayıların hangi aralıklarla üretileceğini ifade eder. Eğer azalan sekans yaratmak isterseniz INCREMENT BY değerini negatif olarak ayarlamanız gerekmektedir. Varsayılan INCREMENT BY değeri 1'dir ve özellikle tanımlanmadığı zaman geçerlidir.

MINVALUE: Azalan sekanslar için sınırlayıcı değer olabilir çünkü bir sekansın gidebileceği en az değeri ifade eder. Azalan sekanslar için özellikle bir MINVALUE tanımlanmaz ise sekansın gideceği limitte -10 üzeri 26 olacaktır.

MAXVALUE: Artan sekanslar için sınırlayıcı değer olabilir çünkü bir sekansın gidebileceği en fazla değeri ifade eder. Artan sekanslar için özellike bir MAXVALUE tanımlanmaz ise sekansın gideceği limitte 10 üzeri 27 olacaktır.

CYCLE: Sınırlayıcı eşik değere ulaştıktan sonra sekansın göstereceği davranışı belirler. CYCLE ifadesi ile sekans yaratılmış ise eşik değere ulaşıldıktan sonra sekans, başlangıç noktasına geri döner.

NOCYCLE: Bir sekans yaratırken varsayılan olarak NOCYCLE yaratılır yani sınırlayıcı eşik değere ulaşıldığı zaman sekans tamamlanır.

CACHE: Hafızada tutulması planlanan ve istenen sekans bloklarını ifade eder. Varsayılan blok sayısı 20'dir.

NOCACHE: Data Dictionary'i sürekli olarak zorlayacak bu özellikle birlikte sekansın numaraların her güncellemede tutulmasını isteyebiliriz. Bunu yaparsak sekansın performansı azalacak ancak oluşturulacak olan sayılar arasında bir kopukluk olmaması garanti altına alınacaktır.

Önemli; bir sekans yaratılırken START WITH mutlaka MINVALUE'dan büyük veya eşit olmalıdır. Aksi halde;


SQL> CREATE SEQUENCE ogan_seq START WITH -100;
CREATE SEQUENCE ogan_seq START WITH -100
*
ERROR at line 1:
ORA-04006: START WITH cannot be less than MINVALUE

Sekanslar basit bir drop ifadesi ile düşürülebilirler;


SQL> DROP SEQUENCE ogan_seq;

Sequence dropped.

Birkaç önemli noktaya daha değinmek isterim. Sekansların objelerle bir ilişkisi yoktur. Yani tablodaki güncellemelerle veya tablonun düşürülmesi ile sekansın numaraları arasında bir bağlantı bulunmamaktadır. İlerideki örneklerde bunu göstereceğim.

SQL> CREATE SEQUENCE ogan_seq
  2  START WITH 1
  3  INCREMENT BY 1
  4  CYCLE
  5  MAXVALUE 100
  6  CACHE 30;

Sequence created.

SQL> select sequence_name, min_value, max_value, increment_by, cycle_flag, cache_size, last_number
  2  from user_sequences
  3  where sequence_name = 'OGAN_SEQ';

SEQUENCE_NAME                   MIN_VALUE  MAX_VALUE INCREMENT_BY C CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - ---------- -----------
OGAN_SEQ                                1        100            1 Y         30           1

Peki şimdi sekansların kullanımına geçelim ve yukarıdaki örneği devam ettirelim;

Sequence Kullanımı

Hemen bir hata ile başlamak istiyorum. Yukarıdaki ogan_seq sekansını yarattıktan sonra;

SQL> select ogan_seq.currval from dual;
select ogan_seq.currval from dual
       *
ERROR at line 1:
ORA-08002: sequence OGAN_SEQ.CURRVAL is not yet defined in this session

Neden ORA-08002 ? Bağlantımız içerisinde önce NEXTVAL göndermemiz gerekiyor ki CURRVAL ile sekansın şu andaki değerini görelim!

SQL> select ogan_seq.nextval from dual;

   NEXTVAL
----------
         1

SQL> select sequence_name, min_value, max_value, increment_by, cycle_flag, cache_size, last_number
  2  from user_sequences
  3  where sequence_name = 'OGAN_SEQ';

SEQUENCE_NAME                   MIN_VALUE  MAX_VALUE INCREMENT_BY C CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - ---------- -----------
OGAN_SEQ                                1        100            1 Y         30          31

SQL> select ogan_seq.currval from dual;

   CURRVAL
----------
         1

--> Buraya dikkat! Oracle gördüğünüz gibi LAST_NUMBER sütununu, USER_SEQUENCES görüntüsünde 31 olarak ifade etti ancak currval bize kesin ve net sonucu verdi, yani 1'i. 

SQL> select ogan_seq.nextval from dual;

   NEXTVAL
----------
         3

SQL> select ogan_seq.currval from dual;

   CURRVAL
----------
         3

SQL> select sequence_name, min_value, max_value, increment_by, cycle_flag, cache_size, last_number
  2  from user_sequences
  3  where sequence_name = 'OGAN_SEQ';

SEQUENCE_NAME                   MIN_VALUE  MAX_VALUE INCREMENT_BY C CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - ---------- -----------
OGAN_SEQ                                1        100            1 Y         30          31

--> 31'i geçecene kadar devam edersek;

SQL> select ogan_seq.nextval from dual;

   NEXTVAL
----------
        32

SQL> select ogan_seq.currval from dual;

   CURRVAL
----------
        32

SQL> select sequence_name, min_value, max_value, increment_by, cycle_flag, cache_size, last_number
  2  from user_sequences
  3  where sequence_name = 'OGAN_SEQ';

SEQUENCE_NAME                   MIN_VALUE  MAX_VALUE INCREMENT_BY C CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - ---------- -----------
OGAN_SEQ                                1        100            1 Y         30          61

--> Data dictionary'deki sekans bilgimiz CAHCE 30 olduğu için 31'i geçtiğimiz zaman yeni LAST_NUMBER değeri 61 olarak değiştirildi. Peki NOCAHCE olsaydı?

SQL> CREATE SEQUENCE ogan_seq
  2  START WITH 1
  3  INCREMENT BY 1
  4  CYCLE
  5  MAXVALUE 100
  6  NOCACHE;

Sequence created.

SQL> select sequence_name, min_value, max_value, increment_by, cycle_flag, cache_size, last_number
  2  from user_sequences
  3  where sequence_name = 'OGAN_SEQ';

SEQUENCE_NAME                   MIN_VALUE  MAX_VALUE INCREMENT_BY C CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - ---------- -----------
OGAN_SEQ                                1        100            1 Y          0           1

--> CACHE boyutu 0 (sıfır)

SQL> select ogan_seq.nextval from dual;

   NEXTVAL
----------
         5

SQL> select ogan_seq.currval from dual;

   CURRVAL
----------
         5

SQL> select sequence_name, min_value, max_value, increment_by, cycle_flag, cache_size, last_number
  2  from user_sequences
  3  where sequence_name = 'OGAN_SEQ';

SEQUENCE_NAME                   MIN_VALUE  MAX_VALUE INCREMENT_BY C CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - ---------- -----------
OGAN_SEQ                                1        100            1 Y          0           6

--> LAST_NUMBER sütunu bu sefer currval değerinin bir fazlasını gösterecek şekilde sürekli olarak değişimlerden sonra güncellendi.

SQL> rollback;

Rollback complete.

SQL> select ogan_seq.currval from dual;

   CURRVAL
----------
         5

--> Rollback komutu ile sekans numaramız en başa dönmedi. Rollback bir transaction'ı geri almaktadır buna karşın sekanslar transaction bağımsız olarak, data dictionary'de güncellenmektedir. Tabii sekansların yine de transaction'la ilgileri bulunmaktadır. Bir örnek;

SQL> create table ogan_deneme
  2  as
  3  select * from all_users;

Table created.

SQL> update ogan_deneme
  2  set user_id = ogan_seq.nextval;

126 rows updated.

SQL> select * from ogan_deneme where username = 'SYS';

USERNAME                          USER_ID CREATED
------------------------------ ---------- ---------
SYS                                     6 23-FEB-09

-- Şimdi bir aksilik olduğunu farkettik ve rollback istedik;

SQL> rollback;

Rollback complete.

SQL> update ogan_deneme
  2  set user_id = ogan_seq.nextval;

126 rows updated.

SQL> commit;

Commit complete.

SQL> select * from ogan_deneme where username = 'SYS';

USERNAME                          USER_ID CREATED
------------------------------ ---------- ---------
SYS                                    32 23-FEB-09

--> SYS'nin önceki kullanıcı numarası 6 şimdi 32 olmuş. ogan_seq'den hatırlarsanız eğer sınırlayıcı eşik değer 100'dü ve 100'e gelindikten sonra başa dönecekti. Tablomuzda 126 kayıt olduğu anlaşıldı ve 100'den sonra başa dönüldü. ogan_seq'in bu operasyondan önce kaldığı değer 5'di.

Bir diğer karşılaşılabilecek tehlikeli konulardan birisi de sekans'ın alabileceği azami değer ile tablonun içerisindeki kayıtlar arasındaki ilişkidir;

SQL> DROP SEQUENCE ogan_seq;

Sequence dropped.

SQL> CREATE SEQUENCE ogan_seq MAXVALUE 10 NOCYCLE;

Sequence created.

SQL> SELECT ogan_seq.nextval
  2  FROM ogan_deneme;
ERROR:
ORA-08004: sequence OGAN_SEQ.NEXTVAL exceeds MAXVALUE and cannot be instantiated

no rows selected

--> Burada gördüğümüz gibi sekans 10'a geldiği zaman ömrünü tamamladı ve 126 kayıtlık ogan_deneme tablosu için bir gösterimde bulunamadan hata aldı.

Sequence Değiştirmek (ALTER)

Sekansların yapıları gereği, sekans nextval değerini alter komutu ile değiştiremezsiniz. Ancak aşağıdaki yaklaşımları uygulayabilirsiniz;

1) Düşür ve sekansı yeniden yarat (Bunu yaparsanız bütün haklarınız kaybolacak ve bağımlı objeler geçersiz kılınacak).
2) Yeterince NEXTVAL komutu ile sekansın istediğimiz numaraya gelmesini sağlayarak.
3) Sekansın INCREMENT BY değerini ALTER komutu ile değiştirerek istediğimiz NEXTVAL oluşuncaya kadar devam etmek.

SQL> ALTER SEQUENCE ogan_seq
  2  INCREMENT BY 1001;
ALTER SEQUENCE ogan_seq
*
ERROR at line 1:
ORA-04005: INCREMENT must be less than MAXVALUE minus MINVALUE

--> Kaş yaparken göz çıkarmayalım :)

SQL> ALTER SEQUENCE ogan_seq
  2  MAXVALUE 10001;

Sequence altered.

SQL> ALTER SEQUENCE ogan_seq
  2  INCREMENT BY 1001;

Sequence altered.

SQL> SELECT ogan_seq.NEXTVAL
  2  FROM dual;

   NEXTVAL
----------
      1011

SQL> SELECT ogan_seq.NEXTVAL
  2  FROM dual;

   NEXTVAL
----------
      2012

SQL> DROP SEQUENCE ogan_seq;

Sequence dropped.

Sekanslarla ilgili başlıca işlemleri yukarıda özetlemeye çalıştım. Bununla birlikte olası hataları ve nerede yanlış yapabileceğimizi de ifade etmek istedim.

İyi çalışmalar.

Ogan

Hiç yorum yok:

Takip et: @oganozdogan