Tek kullanıcılı bir veritabanında, bir kullanıcı aynı verileri aynı anda değiştiren diğer kullanıcılar için endişe duymadan verileri değiştirebilir. Ancak, çok kullanıcılı bir veritabanında, aynı anda birden fazla transaction içindeki ifadeler aynı verileri güncelleyebilir. Eşzamanlı olarak gerçekleştirilen transactionlar anlamlı ve tutarlı sonuçlar üretmelidir. Aynı anda aynı tablo hatta aynı satırlar üzerinde işlem yapan çok kullanıcılı sistemler artık kaçınılmaz.Hal böyle olunca bilgilerin tutarlılığının sağlanması istenmeyen sonuçları almamak açısından çok önemlidir. Çok kullanıcılı bir veritabanı aşağıdakileri sağlamalıdır.

  • Kullanıcıların aynı anda verilere erişebileceği güvencesi (veri eşzamanlılığı – data concurrency). Kısaca pek çok kullanıcının aynı anda aynı dataya ulaşabilmesi durumu
  • Her kullanıcının, kendi işlemleri tarafından yapılan görünür değişiklikler ve diğer kullanıcıların taahhüt ettiği işlemler de dahil olmak üzere verilerin tutarlı bir görüntüsünü (veri tutarlılığı – data consistency) gördüğü güvencesi. Kısaca her bir kullanıcının kendisinin ya da bir başka kullanıcının transaction ı aynı anda calişsa bile tutarlı bir data setine sahip olabilmesi şeklinde özetlenebilir.

Transactionlar aynı anda çalıştığında tutarlı işlem davranışını tanımlamak için, veritabanı araştırmacıları serializability adı verilen transaction isolation modeli tanımladılar. Bu konu ile ilgili detaylı bilgiyi bir önceki yazımda vermiştim. Serializable bir transaction, başka hiçbir kullanıcı veritabanındaki verileri değiştirmemiş gibi görünmesini sağlayan bir ortamda çalışır.

Transactionlar arasında bu tür bir isolation derecesi genellikle arzu edilmekle birlikte, birçok uygulamayı serializable modda çalıştırmak, uygulama verimini ciddi şekilde tehlikeye atabilir. Eşzamanlı çalışan transactionların tamamen isolationı, bir transactionın başka bir transaction tarafından sorgulanan bir tabloya ekleme yapamayacağı anlamına gelebilir. Kısacası, gerçek dünyadaki düşünceler genellikle mükemmel transaction isolationı ve performans arasında bir uzlaşma gerektirir.

Oracle Database, multiversion consistency modeli ve çeşitli lock ve transaction türlerini kullanarak veri tutarlılığını(consistency) korur. Bu şekilde, veritabanı, eşzamanl ı(concurrent) olarak birden fazla kullanıcıya veri görünümü sunabilir, bu da her bir görünümün zaman içindeki bir noktayla tutarlı olmasını sağlar. Farklı veri bloğu versiyonları aynı anda mevcut olabileceğinden, işlemler bir sorgu için gereken zamanda işlenen verilerin versiyonunu okuyabilir ve zaman içindeki tek bir noktayla tutarlı olan sonuçları döndürür.

Multiversion Read Consistency

Oracle Veritabanında, multiversioning, aynı anda birden fazla veri versiyonu gerçekleştirme yeteneğidir. Oracle Database, multiversion okuma tutarlılığını korur. Oracle veritabanının sorguları aşağıdaki özelliklere sahiptir:

  • Read-consistent queries

Bir sorgu tarafından döndürülen veriler zaman içinde bir point için kesin ve tutarlıdır.

Not: Oracle Database hiçbir zaman,  kirli okumalara (dirty read) izin vermez. Dirty Read bir başkası tarafından (bir başkasının transaction’ı tarafından) henüz commit edilmemiş verinin, diğer kullanıcının transaction’ı tarafından okunmasına denir.

  • Nonblocking queries

Veritabanında da sorgulayanlar ve DML işemi yapanlar birbirlerini engellemez.

Oracle’ın garanti ettiği 2 tane uyumluluk kontrolü vardır. Bunlar, Statement level read consistency ve Transaction level read consistency dir. Bunlar, Oracle’ın her zaman bir sorgunun veri ile döneceğini ve her sorgunun veriye ulaşacağını garanti eden koşullardır.

Statement-Level Read Consistency

Oracle Database her zaman statement düzeyinde okuma tutarlılığını(read consistency) zorlar; bu, bir sorgu tarafından döndürülen verilerin zaman içinde tek bir nokta için kararlı ve tutarlı olduğunu garanti eder. Tek bir SQL ifadesinin tutarlı olduğu nokta, transaction isolation level ve sorgunun yapısına bağlıdır:

  • Read committed isolation level, bu nokta sorgunun açıldığı zamandır. Örneğin, bir SELECT ifadesi SCN 1000’de açılırsa, bu ifade SCN 1000 ile tutarlıdır.
  • Serializable veya read-only transaction, bu nokta transactionın başladığı zamandır. Örneğin, bir transaction SCN 1000’de başlarsa ve bu transactionda birden fazla SELECT ifadesi varsa, her ifade SCN 1000 ile tutarlıdır.
  • Bir Flashback Sorgu işleminde (SELECT … AS OF), SELECT ifadesi, zamandaki noktayı açıkça belirtir. Örneğin, bir tabloyu geçen perşembe saat 2: 00’de göründüğü gibi sorgulayabilirsiniz.

Yani transaction t anında bir sorgulama başlattığında bu t anına kadar olan bilgileri getirme garantisi vardır.Yani t+1 anında bir data girildiğinde bu datalar t anında başlatılan sorguda görülmezler.Peki bu değişiklikler olduğu halde nasıl tutarlı data getiriliyor.Oracle bunu rollback segment bilgisini okuyarak sağlar.

Transaction-Level Read Consistency

Oracle Database ayrıca, transaction-level read consistency olarak bilinen bir transaction daki tüm sorgulara okuma tutarlılığı sağlayabilir. Bu durumda, bir transaction daki her ifade aynı zaman diliminde veri görür; bu transactionın başladığı zamandır.

Serializable transaction tarafından yapılan sorgular, transactionın kendisinde yapılan değişiklikleri görür. Örneğin, employees güncelleyen ve ardından employees sorgulayan bir transaction güncellenen verileri görecektir. Transaction-level read consistency repeatable read isolation Leveldir ve sorguyu phantom read’a maruz bırakmaz.

Yani , transaction-level read consistency sinde statement-level read consistency sinden farklı olarak bir transaction içersinde tek bir sorgulama yerine birden fazla sorgulama için aynı garanti verilmektedir.Bu sayede bir sorgulama hiçbir zaman “dirty read” yapmayacağı gibi transaction ların yaptığı commit lerdende etkilenmez.Bu sadece SELECT için değil koşul içeren DELETE, UPDATE,sorgulama ile yapılan INSERT işlemlerinde de geçerlidir

Read Consistency and Undo Segments

Multiversion read consistency modelini yönetmek için, bir tablo aynı anda sorgulandığında ve güncellendiğinde veritabanı read consistency sağlaması için veri kümesi oluşturması gerekir. Oracle Database, verileri geri alma yoluyla(undo data aracılığıyla) okuma tutarlılığı(read consistency) sağlar. Bir kullanıcı verileri değiştirdiğinde, Oracle veritabanı, segmentleri geri almak için yazdığı undo segmentlerini oluşturur .

Undo segmentleri, uncommitted veya son zamanlarda değiştirilmiş transactionlar ile değiştirilen eski veri değerlerini içerir. Bu nedenle, aynı verinin birden fazla sürümü (verisyonu), hepsi zaman içindeki farklı noktalarda, veritabanında bulunabilir. Veritabanları, verilerin read-consistenti sağlamak ve nonblocking sorguları etkinleştirmek için farklı noktalardaki verilerin anlık görüntülerini(snaphot) kullanabilir.

Single instnace ve Oracle Real Application Cluster (Oracle RAC) ortamlarında read consistency garanti edilir. Oracle RAC, bir veritabanı instance’ından diğerine veri bloklarının read-consistent aktarmak için cache fusion olarak bilinen bir cache-to-cache bloğu aktarım mekanizması kullanır.

Aşağıdaki resimde statement-level read consistency sağlamak için  undo veri kullanan bir sorgu gösterir read committed isolation level.

Bu grafik, altında “SCN 10023″ yazan bir SELECT ifadesini gösterir. Açıklamada, her biri farklı bir SCN: 10021, 10021, 10024 (shaded blok), 10008, 10024 (shaded blok), 10011, 10021 şeklinde bir bloklar sütunu bulunur. ” Scan Path ” etiketli bir ok, SELECT ifadesinden sütun boyunca sonuna kadar gider, ancak ok, shaded blokların sağına çıkar ve sütunun sağına asılı olan bloklardan geçer: biri SCN 10006 ve diğeri ile SCN 10021 ile. Undo Segment etiketli bir daire bu iki bloğa işaret eder.

Veritabanı bir sorgu adına veri blokları alırken, veritabanı her sorgudaki verinin sorgu başladığında bloğun içeriğini yansıtmasını sağlar. Veritabanı, bloğun, sorgu işlemenin başladığı noktadaki bloğu yeniden yapılandırması için gereken değişiklikleri geri alır.

Veritabanında işlemlerin sırasını garanti altına almak için SCN adı verilen internal sıralama mekanizması kullanılmaktadır. SELECT ifadesi execute aşamasına girerken, veritabanı, sorgunun çalışmaya başladığı sırada kaydedilen SCN’yi belirler.  Yukarıdaki şekilde bu SCN 10023’tür. Sorgu yalnızca SCN 10023 ile ilgili taahhütlü verileri görür.

Yukarıdaki şekilde 10023’ten sonra SCN’lere sahip bloklar, SCN 10024’e sahip iki blokta gösterildiği gibi değiştirilmiş verileri gösterir. SELECT ifadesi, blokta yapılan değişikliklerle tutarlı bir versiyonunu gerektirir. Veritabanı, geçerli veri bloklarını yeni bir buffere kopyalar ve blokların önceki sürümlerini yeniden oluşturmak için undo verilerini uygular. Bu yeniden yapılandırılmış veri bloklarına consistent read (CR) klonları denir. Yukarıdaki şekilde, veritabanı iki CR klonu yaratır: bir blok SCN 10006’ya ve diğer blok ise SCN 10021’e uyumludur. Bu şekilde, Oracle Database dirty read’i önler.

Read Consistency and Transaction List

Her segment bloğunun blok başlığı, ilgili bir transaction list (ITL) içerir. Veritabanı, bloğu değiştirmeye başladığında bir transaction gerçekleştirilip gerçekleştirilmediğini belirlemek için ITL’yi kullanır.

ITL’deki girişler, hangi transactionların hangi satırların kilitlendiğini(lock) ve bloktaki hangi satırların commit ve uncommit edilmemiş değişiklikler içerdiğini açıklar. ITL, veritabanında yapılan değişikliklerin zamanlaması hakkında bilgi sağlayan undo segmentindeki transaction tablosuna işaret eder.

Bir anlamda, block header, bloktaki her satırı etkileyen transactionların geçmişini içerir. CREATE TABLE ve ALTER TABLE ifadelerinin INITRANS parametresi tutulan işlem geçmişi miktarını kontrol eder.

LOCK Mekanizması

Genel olarak, çok kullanıcılı veritabanları, veri eşzamanlılığı(concurrency), tutarlılığı(consistency) ve bütünlüğü(integrity) ile ilgili sorunları çözmek için bir tür veri kilitleme(lock) yöntemi kullanır. .Lock, aynı kaynağa ulaşan birden fazla transaction ın sebep olacağı istenmeyen durumları engellemeye yarayan mekanizma olarak kabaca açıklanabilir.Burada kaynaktan kasıt tablo, satır gibi kullanıcı objeleri olabileceği gibi kullanıcıların göremediği Oracle ın kendi data yapısı ya da data dictionary satırları olabilir.

ANSI/ISO standartlarına göre Transaction Isolation(Soyutlama) Seviyeleri

Hem ANSI hem de ISO/IEC tarafından benimsenen SQL standardı, dört düzeyde transaction isolation tanımlar. Bu seviyelerin transaction processing verimi üzerinde farklı etkileri vardır. Bu konuyu detaylı olarak bir önceki yazımda yazmıştım. Yazı bütünlüğü açısından özetini burayada yapıştırıyorum. Detaylı yazı için burayı okuyabilirsiniz.

İsolation level, eşzamanlı olarak yürütme işlemleri arasında önlenmesi gereken durumlar cinsinden tanımlanır. Önlenebilir durumlar;

  • Dirty reads : Bir başkası tarafından (bir başkasının transaction’ı tarafından) henüz commit edilmemiş verinin, diğer kullanıcının transaction’ı tarafından okunmasına denir.
  • Nonrepeatable (fuzzy) reads : Bir Transaction’ın aynı kaydı iki kere okuduğunda farklı değerler (ilk okumadan sonra sonlanan başka bir Transaction’dan dolayı) elde edebileceği anlamına gelir. İki eş zamanlı çalışan Transaction’ ımız olduğunu düşünelim. Transaction’ lardan birisi veri çekmiş olsun. Özellikle çektiği belirli bir satır olabilir. Diğer Transaction’ da bu belirli satırı veya başkalarını güncellesin ve işlemi onaylansın (Commit). İşte bu noktadan sonra, diğer çalışmakta olan Transaction aynı satırlara yeniden baktığında verilerin değişmiş olduğunu görecektir.
  • Phantom reads : Bir Transaction’ın ilk yaptığı sorgudan dönen kayıtların aynı sorguyu aynı Transaction içerisinde ikinci kez yapması ile farklı sayıda kayıt (yine ilk sorgudan sonra başka Transaction tarafından tabloya eklenen veya silinen ve commit edilen kayıtlar dolayısıyla) dönebilmesi anlamına gelir. Bu, Non-Repeatable ready’e benzer, ancak satır sayısının ekleme veya silme ile değiştirilmesi dışında.

SQL standardı, belirli bir isolation seviyesinde çalışan bir transaction tecrübe edilmesine izin verilen olgu olarak dört isolation level tanımlar.

Isolation Level Dirty Read Nonrepeatable Read Phantom Read
Read uncommitted Possible Possible Possible
Read committed Not possible Possible Possible
Repeatable read Not possible Not possible Possible
Serializable Not possible Not possible Not possible

Oracle Veritabanları için Transaction Isolation(Soyutlama) Seviyeleri

Yukarıda tabloda bulunan isolation seviyeleri ANSI standartıdır. Standart, her isolation seviyesi için izin verilen veya önlenebilecek durumlarla tanımlanır. Oracle Databasede, aşağıdaki transaction isolation seviyelerini destekler;

  • Read Committed Isolation Level : Oracle’ın standart-default isolation seviyesidir. Kısaca Transaction ın basladıgı t anından evvelki commit edilmiş kayıtları görür.
  • Serializable Isolation Level : Read Committed a ek olarak aynı transaction ın yaptıgı INSERT , UPDATE ve DELETE işlemlerinin sonuçlarını da görür.
  • Read Only Isolation Level : Read Committed gibidir ama INSERT, UPDATE ve DELETE işlemlerinin yapılmasına izin vermeyen transaction lardır.

NOT : Oracle Read Uncommited’a izin vermemektedir.

Farklı transaction larda farklı “isolation level” yapmak isteyebiliriz. Bunu sağlamak için ya uygulamamızın basına SET TRANSACTOIN ile başlayan aşağıdaki kodu ekleriz :

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET TRANSACTION READ ONLY;

ya da  session bazlı tercih de yapabiliriz.Örneğin :

ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE;
ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;

Oracle,  SQL  standartlarında belirtilen READ COMMITED ve  SERIALIZABLE isolation  seviyelerini desteklemektedir.  Ayrıca  Oracle,  SQL  standartlarındaki  diğer iki  isolation   seviyesi   olan READ  UNCOMMITED ve REPEATABLE READ ile “anlatılmak istenen” kavramları da desteklemektedir ancak Oracle’ın bu konuya yaklaşımı SQL standartlarında olduğu gibi sadece hangi anomalilere izin verilecek veya verilmeyecek gibi bir kavram üzerine kurulu değildir.

Örneğin SQL standartları tanımında READ COMMITTED size tutarlı sonuç (consistent results) vermek zorunda değildir ve READ UNCOMMITTED, birbirini bloklamayan okumalar (nonblocking reads) yapmak için gerekli olan isolation seviyesidir. Halbuki,  Oracle’ın READ COMMITTED yaklaşımında tutarlı okuma yapabilmek için gerekli olan yapı mevcuttur. Diğer veritabanlarında READ COMITTED isolation seviyesinde veritabanında daha önce var olmamış değerler okunabilir. Ayrıca, bloklamayan okuma  yapmak  için Oracle’ın READ UNCOMMITTED isolation seviyesine ihtiyacı yoktur. Oracle’daki read zaten hiçbir zaman bloklanmaz.

Oracle’ın, Isolation Seviyeleri’ne yaklaşımının diğer veritabanlarından farklı olmasının temelinde multi-version concurrenct control (MVCC) yapısı yer alır. Bu yapı ile Oracle, bir verinin birden çok versiyonunu çalışan sorgunun başlangıç anındaki sistem numarasına göre çıkarabilmektedir. MVCC ve tutarlı  okuma  yapısı  ile  Oracle’ın  isolation  seviyelerine  yaklaşımının  detaylarına  aşağıdaki maddelerde yer verilmiştir.

Read Committed Isolation Level

Oracle’ın standart-default isolation seviyesidir.  Transaction tarafından yürütülen her sorgu yalnızca transactiondan önce işlenen verileri görür. Bu isolation seviyesi, az sayıda işlemin çakışma olasılığı olan veritabanı ortamları için uygundur. Kısaca Transaction ın basladıgı t anından evvelki commit edilmiş kayıtları görür.

Okunmuş bir transactiondaki sorgu, sorgu devam ederken işlenen verileri okumaktan kaçınır.

Örneğin, bir sorgu milyon satırlık bir tablonun taranması sırasında yarıdaysa ve farklı bir transaction 950.000 satırına bir güncelleme gerçekleştirdiyse, 950.000 satırını okuduğunda, sorgu bu değişikliği görmez. Ancak, veritabanı diğer transactionların bir sorgu tarafından okunan verileri değiştirmesini engellemediğinden, diğer transactionlar sorgu yürütmeleri arasında veri değiştirebilir. Bu nedenle, aynı sorguyu iki kez çalıştıran bir transactionda Phantom Read görülebilir.

  • Transaction Level:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • Session Level:
ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;

Bu  isolation  seviyesine  Oracle’ın ve diğer veritabanlarının yaklaşımlarından bakalım;Aşağıdaki sorguyu aşağıda tabloda gösterilen ACCOUNTS tablosu üzerinde çalıştırdığımızı düşünelim.

select sum(account_balance) from accounts;
Row Account Number Account Balance Locked?
1 123 $500.000
2 456 $240.025
350,000 987 $100.000

Select sorgusu row1, row2… şeklinde ilerleyerek çalışırken ve tablonun ortalarında bir yerlerdeyken başka bir transaction’ın update çalıştırarak account number 123’den account number 987’ye $400.000   aktardığını  fakat  COMMIT  göndermediğini  düşünelim.  O  zaman  tablomuz  aşağıdaki  gibi gözükecektir.

Zaman T1Transaction: SELECT T2 Transaction: UPDATE
T1 1.row okunur. SUM=$500.000
T2 2.row okunur. SUM=$740.025
T3 1. row’u UPDATE eder. 1. row’un yeni değeri $100.00[1. Row Locklanır.]
T4 350,000. row’u UPDATE eder. 350,000. row’un yeni değeri $500.00 [350,000. Row Locklanır.]
T5
T6 SELECT sorgusu 350,000. row’a ulaşır… Sorgunun bu kısmında Oracle ve MVCC kullanmayan veritabanları farklı biçimde davranır.

 

Select sorgusu 350,000. row’a ulaştığında ;

Oracle multi-versioning kullanarak tutarlı okuma (consistent  read)    yapar;  350,000.  row’un update gördüğünü (commit olsun olmasın) anlayarak okumaya  başlandığı  andaki  halini  tekrar  oluşturur  (UNDO  segmentinden)  ve  $100.00  değerini döndürür.

MVCC kullanmayan diğer  veritabanlarında ise; select sorgusu yapan transaction 350,000. row’a ulaştığında; bu satırı update etmiş olan diğer transaction’ın commit göndererek lock’ı kaldırmasını bekler. Buradan anlaşılıyor ki MVCC yapısı ile row versiyonlaması sunmayan veritabanlarında okuma yapan sorgular yazma yapanlar tarafından bekletilebiliyor. (writers block readers). Daha vahim olan ise; commit için beklemekte olan sorgu, yanlış bir değeri okumak için beklemektedir.  Sorgunun başladığı andaki değer olan $100.00 okumak yerine $500.00 değeri okuyarak arada transfer olmuş olan $400.00 değerini iki kez hesaba katmış olur. (1.row ve 350,000.row’ların ikisinde de $500.00 okundu.)

NOT : Oracle kullanıcı tarafından hiçbir işlem yapmadan veri tutarlılığını(consistent) garanti eden her sorgu için ayarlanmış tutarlı bir sonuç sağlar.

NOT : SELECT listesi PL / SQL function içeriyorsa, veritabanı, SQL düzeyinde değil, PL / SQL function kodu içinde çalıştırılan SQL için statement-level read consistency uygular. Örneğin, bir function verileri başka bir kullanıcı tarafından değiştirilen ve kabul edilen bir tabloya erişebilir. SELECT fonksiyonunun her bir çalışması için, read-consistent yeni bir snaphot oluşturulur.

Serializable Isolation Level

En çok kısıtlama ile en yüksek isolation seviyesi sağlayan SERIALIZABLE isolation seviyesinde transaction’lar sanki başka hiçbir sorgunun çalışmadığı bir ortamda tek başlarına çalışıyorlarmış gibi bir isolation’a sahiptirler. Okunan herhangi bir satır veya sonuç kümesi, transaction boyunca aynı değerlere sahip olacaktır. Read Committed a ek olarak aynı transaction ın yaptıgı INSERT , UPDATE ve DELETE işlemlerinin sonuçlarını da görür.

Oracle’da SERIALIZABLE isolation seviyesinin bulunmasının asıl amacı; statement bazında olan okuma tutarlılığının (read consistency), transaction bazında yapılabilmesini sağlamaktır. Yine UNDO (rollback) segment kullanılarak, bu sefer statement yerine transaction’ın başladığı andaki görüntü oluşturularak consistent okuma yapılması sağlanır.

  • Transaction Level:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  • Session Level:
ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE;

Ancak; Oracle’da serializable isolation seviyesinin bir bedeli vardır; eğer ki serialiazable isolation seviyesinde çalışan transaction; çalışma anından sonra başka bir transaction tarafından değiştirilmiş bir satırı değiştirmeye kalkarsa aşağıdaki hatayı alır:

ERROR at line 1:

ORA-08177: can’t serialize access for this transaction

Oracle herşeyden önce yüksek performans hedefleyen bir OLTP veritabanıdır, bu sebeple serialization kavramını optimistic (iyimser) mantık ile ele alır. Bu şu demektir; bir transaction’ın update etmeye çalıştığı kayıt çok büyük ihtimalle aynı anda başka transaction’lar tarafından update edilmek istenmeyecektir yani bu ihtimal genelde zayıftır. Özellikle OLTP uygulamalarında durum buna çok yakındır ve bu yüzden Oracle bu şekilde bir riski alacak iyimser bir yaklaşımla, transaction sırasında başka bir transaction’ın aynı verileri değiştirmeyeceği varsayılarak tasarlanmıştır. Risk sonuç verirse şu olur; Oracle veritabanı; diğer veritabanlarından farklı olarak sanki yüksek eşzamanlı yani tam performansla çalışır, olur da risk sonuç vermeyip korkulan olursa ORA-08177 hatası alınır.

Zaman T1Transaction T2 Transaction
T1 SQL>alter session set isolation_level=serializable;

SQL>update  TEST_TABLE  set  name=’TrA’ where id=1;

T2
T3 ….. SQL>update TEST_TABLE set name=’TrB’ where id=350000;

SQL>COMMIT;

T4 SQL> update  TEST_TABLE  set  name=’TrB’ where id=350000;

 

ERROR: ORA-08177: can’t serialize access for this transaction

 

Oracle’da serialization isolation seviyesi kullanılıyorsa bu risk göz önünde bulundurulmalıdır. Eğer Tablo’de T1 transaction’ının araya başka bir transaction girmesini engellemesi için SELECT … FOR UPDATE sql cümleciğini kullanması gerekir.

Read-Only Isolation Level

SQL standartlarında tanımlanmış olan dört adet isolation seviyelerine ek olarak Oracle’da READ ONLY isminde  bir  isolation  seviyesi  daha  vardır. READ ONLY isolation seviyesi REPEATABLE READ veya SERIALIZABLE gibi çalışır fakat bu seviyede çalışan bir transaction veritabanında modfikasyon(DML) yapamaz.

Oracle Veritabanı LOCK Mekanizması

Oracle LOCK yapısı, en temel seviyede veri bütünlüğünü ve tutarlılığını sağlamak için yapılmış koruyucu bir mekanizmadır. Bu sayede bir tablo üzerinde DML işlemi çalıştırıldığında yapılmak istenilen değişiklik tam olarak sağlanmadan başka DML işlemine izin verilmemektedir. Locklar, veritabanı eşzamanlılığı (concurrency) ve tutarlılığı (consistency) korumada önemli bir rol oynar.

Oracle ister kullanıcı kaynağı ile ilgili olsun ister sistem kaynağı ile ilgili olsun gerektiği hallerde uygun LOCK mekanizmasını devreye sokar. Ama istendiğinde LOCK mekanizmasının tayinini kullanıcıya da bırakır. Oracle varsayılan olarak gerekli en alt seviye lock mekanizmasını devreye sokar. Peki kac ceşit lock vardır? Exclusive ve share mod olmak üzere 2 farklı modda lock tan bahsedilebilir.

  • Exclusive lock mode : Exclusive Lock ta kaynağın paylaşımı engellenir dolayısıyla datayı değiştirme durumunda kullanılır.
  • Share lock mode : Share modda ise kaynak yapılacak işleme bağlı olarak paylaşıma acık olabilir.

Transaction hangi modda olursa olsun lock ın bırakılması için commit ya da rollback yapılması gerekir. Kaynağı paylaşma durumu oldugunda karşımıza çıkabilecek durumlardan en basta geleni belki de deadlock hatası alma durumudur. Deadlock aynı kaynağı paylaşan 2 ya da daha fazla transaction ın birbirinin işinin bitmesini beklemesi olarak özetlenebilir. Aşağıdaki örnege bakalım :

transaction sağlıklı şekilde işini yapar.T1 empno = 1000 olansatırı, T2 de empno = 2000 olan satırı lock eder ve işini yapar. B anında T1empno = 2000, T2 de empno = 1000 olan kaydı update etmek için lock mekanizmasını devreye sokar. Ancak bu durumda A anındaki işlemden sonra commit ya da rollback yapılmadıgı için sistem her 2 transaction için lock mekanizmasını o satırlar üzerinden kaldırmamıştır. Bu sebeble B anında T1 ve T2 birbirini beklemeye bailayacaklardır. Oracle deadlock durumunu otomatik olarak fark eder, tespit eden transaction ın tarafında rollback çalıştırır ve bir mesaj ile durumu kullanıcıya bildirir.

Oracle da DML locks , DDL locks ve internal locks olmak üzere 3 farklı otomatik lock tan bahsedilir.

  • DML locks : Data locks olarakta bilinir. Datayı koruma amaçlıdır. Örneğin tablo lock ları tüm tabloyu, satır lockları seçili satıları lock eder.
  • DDL locks : Dictionary locks olarakta bilinir. Objelerin yapılarını korumaktan sorumludur. Örneğin bir tablonun yada view ın tanımı gibi.
  • System Locks : Oracle Database, dahili veritabanı ve bellek yapılarını korumak için çeşitli sistem lockları kullanır. Mesela Datafile lar gibi Oracle kendi sistemi ile ilgili objelerin yapılarının korunmasından sorumludur, bunlar otomatiktir. Bu mekanizmalar kullanıcılara erişemez çünkü kullanıcılar oluşumları veya süreleri üzerinde kontrol sahibi değildir. Latches, mutexes, ve internal locks tamamen otomatiktir.

DML Locks

Data lock olarak da adlandırılan bir DML lock, aynı anda birden fazla kullanıcı tarafından erişilen verilerin bütünlüğünü garanti eder. Örneğin, bir DML lock iki müşterinin bir kitabın son kopyasını bir çevrimiçi kitapçıdan satın almasını önler. DML lock, aynı anda çakışan DML veya DDL işlemlerinin tahrip edici girişimini önler.

DML ifadeleri aşağıdaki kilit türlerini otomatik olarak alır:

  • Row Locks (TX)
  • Table Locks (TM)

Row Locks (TX)

TX kilidi de denilen bir row lock, tek bir satırdaki bir lock’dır. Transaction, INSERT, UPDATE, DELETE, MERGE veya SELECT … FOR UPDATE sorgusu tarafından değiştirilen her satır için bir row lock alır. Transaction commit veya rollback yapana kadar row lock vardır.

Row lock, iki transactionın aynı satırı değiştirmesini önlemek için öncelikle bir kuyruk mekanizması görevi görür. Veritabanı her zaman exclusive modda değiştirilmiş bir satırı locklar, böylece diğer transactionlar kilidi tutan işlem tamamlanana veya geri alınana kadar satırı değiştiremez. Row lock mümkün olan en az kilitlemeyi sağlar ve böylece mümkün olan en iyi eşzamanlılık (concurrency) ve verimi (throughput) sağlar.

Bir transaction bir satır için bir lock alırsa, o zaman transaction aynı zamanda satırı içeren tablo için bir lock alır. Tablo lock, geçerli bir transactiondaki veri değişikliklerini geçersiz kılacak çakışan DDL işlemlerini önler. Aşağıdaki şekilde tablodaki üçüncü sıranın bir güncellemesini gösterir. Oracle Database, otomatik olarak güncellenmiş satıra özel bir lock ve tablonun üstüne özel bir lock yerleştirir.

Aşağıdaki senaryo, Oracle Database’in eşzamanlılık (concurrency) için row lock’ın nasıl kullandığını göstermektedir.

T Session 1 Session 2 Session 3 Açıklama
T0 SELECT employee_id,salary FROM   employees WHERE  employee_id IN ( 100, 101 );

EMPLOYEE_ID  SALARY

———–  ——

100          512

101          600

Üç farklı session aynı anda çalışanların kimliklerini ve maaşlarını 100 ve 101 sorguluyor. Her bir sorgunun döndürdüğü sonuçlar aynı.
T1 UPDATE hr.employees SET salary = salary+100 WHERE employee_id=100; Session 1, çalışan 100’ün ücretini günceller ancak commit etmez. Güncellemede,  session yalnızca güncellenmiş satır için satır düzeyinde bir lock elde eder, böylece diğer sessionların bu satırı değiştirmesini önler.
T2 SELECT employee_id,salary FROM   employees WHERE  employee_id IN ( 100, 101 );

EMPLOYEE_ID  SALARY
———–  ——
100          612

101          600

SELECT employee_id,salary FROM   employees WHERE  employee_id IN ( 100, 101 );

EMPLOYEE_ID  SALARY
———–  ——
100          512
101          600

Her session aynı anda orijinal sorguyu çalıştırır. Session 1, t1 güncellemesinden kaynaklanan 612 maaşını göstermektedir. Session 2 ve 3’teki session 1’in işleminin bitmesini beklemeden sonucu getirir. Veritabanı, session 1’deki güncellemeden önceki haliyle maaşını göstermek için multiversion read consistency kullanır.
T3 UPDATE hr.employee SET salary = salary+100 WHERE employee_id=101; Session 2, çalışanın (101) maaşını güncellemektedir, ancak commit yapmamaktadır. Transaction yalnızca güncellenen satır için bir satır düzeyinde lock edinerek diğer transactionların bu satırı değiştirmesini önler.
T4 SELECT employee_id,salary FROM   employees WHERE  employee_id IN ( 100, 101 );
EMPLOYEE_ID  SALARY
———–  ——100          612101          600
SELECT employee_id,salary FROM   employees WHERE  employee_id IN ( 100, 101 );
EMPLOYEE_ID  SALARY
———–  ——100          512101          700
SELECT employee_id,salary FROM   employees WHERE  employee_id IN ( 100, 101 );
EMPLOYEE_ID  SALARY
———–  ——100          512101          600
Her session aynı anda orijinal sorguyu çalıştırır. Session 1, t1 güncellemesinden elde edilen 612’nin maaşını gösterir, ancak session 2’de yapılan çalışanın (101) maaş güncellemesini göstermez. session 3’teki, oturum 1 ve 2’ye göre değişiklik yapmadan önce maaşları göstermek için okuma tutarlılığını kullanır.

Memorydeki lockların listesini tutmak için bir kilitleme yöneticisi(lock manager) kullanan bazı veritabanlarının aksine, Oracle Database lock bilgisini locklı satırı içeren veri bloğunda saklar. Veritabanı, row lockları almak için bir kuyruk mekanizması kullanır. Bir transaction’ın kilidi açık bir satır için bir lock gerektiriyorsa, transaction veri bloğuna bir lock yerleştirir. Bu transaction tarafından değiştirilen her satır, blok başlığında depolanan transaction id’nin bir kopyasını gösterir. Bir transaction sona erdiğinde, transaction id blok başlığında kalır. Farklı bir transaction bir satırı değiştirmek istiyorsa, lock’ın etkin olup olmadığını belirlemek için transaction id  kullanır. Lock etkinse, session kilit serbest bırakıldığında bildirilmesini ister. Aksi takdirde, transaction kilidi alır.

Table Locks (TM)

TM lock olarak da adlandırılan table lock, bir tablo INSERT, UPDATE, DELETE, MERGE, FOR UPDATE yan tümcesi ile SELECT deyimi veya LOCK TABLE deyimi tarafından değiştirildiğinde bir transactionla elde edilir. DML işlemleri, bir işlem adına tabloya DML erişimini ayırmak ve işlemle çakışacak DDL işlemlerini önlemek için tablo kilitlerini gerektirir.  Bir tale lock aşağıdaki modlardan birinde tutulabilir:

  • Row Share (RS) : Aynı zamanda bir subshare table lock (SS) olarak da adlandırılan bu lock, tablodaki lock’ı tutan transactionın tablodaki satırları lockladığını ve bunları güncellemeyi amaçladığını gösterir. row share lock, tablo için en yüksek eşzamanlılık (concurrency) derecesi sunan en az kısıtlayıcı table lock modudur. Tabloya aynı anda erişime izin verir, ancak kullanıcıların exclusive access için tüm tabloyu locklamasını engellenir.
  • Row Exclusive Table Lock (RX) : Row share ile aynı özelliklere sahip olması ile birlikte share modda lock yapılmasını engeller.Oracle Default lock mekanizmasıdır.DML işlemlerinde oracle row-level lock için bu metodu kullanır.
  • Share Table Lock (S) : Tabloya çoklu erişime izin verir ancak tablo üzerinde herhangi bir DML işlem çalışmasına izin vermez. İndex oluştururken bu metod kullanılır.(sadece okumya izin verir)
  • Share Row Exclusive Table Lock (SRX) : Tablonun tamamının okunmasında sakınca yoktur ancak başka userlar tarafından tablonun locklanmasını engeller ve dml işlemlerinede izin vermez.
  • Exclusive Table Lock (X) : Bu opsiyon tüm tabloyu locklar ve tablonun herhangi bir DML işlemine izin vermez ve tabloya lock konulmasına izin vermez, sadece okumaya izin verir en kısıtlayıcı lock moududur.

Lock ve Foreign Key

OLTP sistemlerde Foreign Key constraintleri veri bütünlüğünü sağlamak için sıkça kullanmaktayız. Foreign Key kullanımı veri bütünlüğünü sağlayabilmek açısından kullanılaması gereken mekanizmaların başında geliyor ancak foreign key constraint kullanırken yapmamız gereken bazı önemli ayrıntılar mevcut bunu atlamamamız gerekiyor. Nedir bu önemli ayrıntı dediğimizde, yapmamız gereken şeyin foreign key olarak belirlediğimiz kolonu indexlemek olduğunu görmekteyiz. Çünkü locklama davranışı, foreign key sütunların indexe eklenip eklenmemesine bağlıdır. Foreign key indexe alınmazsa, alt tablo muhtemelen daha sık kilitlenir, kilitlenmeler olur ve eşzamanlılık azalır. Bu nedenle foreign key hemen hemen her zaman indekslenmelidir. Tek istisna, unique veya primary key hiçbir zaman güncellenmemesi veya silinmemesidir.  Aşağıdaki durumlarda child tablosu full table lock alır;

  • Child tablo foreign key sütununda index yok ise,
  • Bir serssion parent tablodaki proimary keyi değiştirirse.

DDL Locks

Data dictionary (DDL) lock, devam eden bir DDL işlemi nesneye etki ederken veya bu nesneye başvururken şema nesnesinin tanımını korur. DDL işlemleri sırasında yalnızca değiştirilmiş veya başvuruda bulunulan ayrı şema nesneleri kilitlenir. Veritabanı hiçbir zaman tüm veri sözlüğünü kilitlemez.

Oracle Database, gerektiren herhangi bir DDL işlemi adına otomatik olarak bir DDL kilidi edinir. Kullanıcılar açıkça DDL kilitleri isteyemezler. Örneğin, bir kullanıcı stored bir prosedür oluşturuyorsa, Oracle Database prosedür tanımında başvurulan tüm şema nesneleri için otomatik olarak DDL kilitlerini alır. DDL kilitleri, prosedür derlemesi tamamlanmadan önce bu nesnelerin değiştirilmesini veya düşürülmesini önler.

  • Exclusive DDL Locks : Exclusive bir DDL kilidi, diğer sessionların bir DDL veya DML lock almasını önler. Örneğin, ALTER TABLE ile bir sütun eklerken aynı zamanda DROP TABLE yapamayız. Exclusive DDL locklaro, DDL deyimi yürütme ve otomatik işleme süresi boyunca en sonda kalır. Exclusive bir DDL kilidinin alınması sırasında, şema nesnesinde başka bir işlem tarafından başka bir DDL kilidi tutulursa, satın alma eski DDL kilidi serbest bırakılıncaya kadar bekler ve ardından devam eder.
  • Share DDL Locks : Bir kaynak için share bir DDL lock, çakışan DDL işlemleriyle tahrip edici etkileşimi önler, ancak benzer DDL işlemleri için veri eşzamanlılığına izin verir. Örneğin, bir CREATE PROCEDURE çalıştırıldığında, içerdiği başvurulan tüm tabloların DDL locklarını paylaşır. Diğer transactionlar aynı anda aynı tablolara referans veren ve aynı tablolarda aynı anda DDL kilitlerini alan prosedürler oluşturabilir, ancak hiçbir işlem başvurulan tablolarda exclusive bir DDL lock elde edemez.

System Locks

Oracle Database, internal veritabanı ve memory yapılarını korumak için çeşitli sistem lockları kullanır. Bu mekanizmalar kullanıcılara erişemez çünkü kullanıcılar oluşumları veya süreleri üzerinde kontrol sahibi değildir.

Latches

Latch, shared data structures, object, ve file lere çok kullanıcılı erişimi koordine eden basit, düşük seviyeli bir serileştirme mekanizmasıdır. Basit anlamda latchler iki prosesin aynı SGA alanını eşzamanlı güncellemelerinden ve muhtemelen bu olaya bağlı bozulmalardan korur. Yani prosesiın SGA içerisinde memory parçasının tutmmasıdır.Proses bittiğinde ise ilgili latch başka bir prosese verilir. Latch İşletim sisteminden bağımsız değildir. Çünkü bir prosesin ne zaman biteceği ve ne kadar süreceği işletim sistemine bağlıdır. Özellikle, latchler veri yapılarını aşağıdaki durumlardan korur:

  • Birden çok session da eşzamanlı değişiklik
  • Başka bir session tarafından değiştirilirken bir session tarafından okunmak
  • Erişilirken hafızadan ayrılma (yaşlanma- aging out)

Genellikle, tek bir latch SGA’da birden fazla nesneyi korur. Örneğin, DBW ve LGWR gibi background prosesleri veri yapıları oluşturmak için shared pool’dan bellek ayırır. Bu belleği tahsis etmek için, bu prosesler, iki işlemin aynı anda paylaşılan havuzu denetlemeye veya değiştirmeye çalışmasını önlemek için erişimi seri hale getiren shared pool latch kullanır. Bellek tahsis edildikten sonra, diğer işlemlerin parsing için gerekli olan library cache gibi shared pool alanlarına erişmesi gerekebilir. Bu durumda, prosesleri shared poolun tamamı yerine yalnızca library cache kilitler.

Enqueue bir oracle lock mekaizması olmasına karşın , birkaç prosesin aynı zamanlı olarak bir kaynağı kullanımına izin verebilir. Tablo lock ları burada en iyi örnektir. Çünkü iki proses bir tabloyu share modda yada share update modda  lock edebilir.

Latch ve enqueue arasındaki en belirgin fark burada Enqueue İşletim sistemi lock mekanizması tarafından oluşturulabilir ve .Latch ise işletim sistemi lock larından bağımsız olarak meydana gelir.Enqueue  kullanıcının lock içerisinde veri girişine izin verir. Eğer bir proses bir kaynağı lock edebilecek yapıya sahip değilse işletim sistemi tarafında enqueu mekanizmasında FIFO yasasına göre bekelmeye girer.

Diğer bir önemli fark ise latchler enqueu ler gibi kaynağı sürekli tutamazlar.Çünkü belli zamanlama ile proses tekrarlanır ve eğer multi prosessor varsa spin yapabilir. Dolayısıyla beleten tüm prosesler aynı anda işlem yapmayı denerler.

Belleğe karşı yapılan işlemlerin süresi çok kısa olduğundan (tipik olarak nanosaniyeler arasında) ve latch talep sıklığı çok yüksek olduğundan, latch mekanizması çok hafif yükte olma ihtiyacı duyar. Eğer latch zaten kullanımdaysa, Oracle bunun daha fazla kullanımda olmamasını üstlenir, böylece pasif beklemeye gitmekten ziyade, vazgeçmeden önce Oracle operasyonu birkaç sefer daha dener. Bu algoritma, “spin lock” elde etmek olarak adlandırılır ve uykudan önce bu spinlerin sayısı “_spin_count” başlangıç parametresince kontrol edilir. Session spin yoluyla latch elde ederken, ilk defa başarısız olduğu anda 10 milisaniye sonra uyanmak için tekrar deneme yapar. Daha sonraki beklemeler süre içinde artar ve aşırı durumlarda ise bir saniyeyi bile aşabilir. latchler için yoğun çekişmelerden dertli sistemlerde bu beklemelerin cevap sürelerinde ve çıktılarında şiddetli bir etkisi olacaktır.

Performansı en sık etkileyen latchler buffer cache, shared pool area ve redo tamponunu koruyan latchlerdir.

  • Library cache ve shared pool latch:  Bu latchler paylaşımlı SQL komutlarının tutulduğu library cache’i korur. İyi hazırlanmış uygulamalarda bu mandallar için çok az veya hiç çekişme olmaz, ancak bind değişkenleri yerine tam isim kullanan uygulamaların SQL komutlarında library cache çekişmesi yaygın olmaktadır(mesela “WHERE surname=:surname“ yerine “WHERE surname=’TEPE’” kullanılırsa)
  • Buffer Cache zincir latch : Bu latch sessionlar buffer cache’e yazma veya okuma işlemi yapıldığında tutulmaktadır. Avuç dolusu blokları koruyan pek çok sayıda bu latchlerden bulunur. Bu latchlerdeki çekişmeler genellikle “sıcak” bloklara eşzamanlı erişimden kaynaklanır ve en yaygın “sıcak” blok index kökü veya kol bloktur(herhangi bir indeks kök bloğa erişmek zorunda olana kadar)
  • Redo kopya/redo tahsis mandalları: Bu mandallar, redo log tamponunu korur.

Mutexes

Mutual exclusion object (mutex), eşzamanlı işlemlerle erişildiğinde bellekteki bir nesnenin eskimesini veya bozulmasını önleyen düşük düzeyli bir mekanizmadır. Bir mutex bir latche benzer, ancak bir latch tipik olarak bir nesne grubunu korurken, bir muteks tek bir nesneyi korur.

Mutex’ler birçok fayda sağlar:

  • Bir muteks çekişme(contention) olasılığını azaltabilir.
  • Bir latch birden çok nesneyi koruduğu için, prosesler bu nesnelerin herhangi birine aynı anda erişmeye çalıştığında bir tıkanıklık olabilir. Bir grup yerine bireysel bir nesneye erişimi seri hale getirerek, bir muteks kullanılabilirliği arttırır.
  • Bir muteks, latchden daha az bellek tüketir.
  • Paylaşılan moddayken, bir muteks birden çok oturumda eşzamanlı başvuruya izin verir.

Internal Locks

Internal lock latch ve mutekslerden daha üst seviye, daha karmaşık mekanizmalardır ve çeşitli amaçlara hizmet eder.

  • Dictionary cache locks : Bu locklar çok kısa sürelidir ve girdiler değiştirilirken veya kullanılırken dictionary cache deki girişler üzerinde tutulur. Parse edilen ifadelerin tutarsız nesne tanımları görmemesini garanti ederler. Dictionary cache lockları shared veya exclusive olabilir. Shared lockları parse tamamlandığında serbest bırakılırken, DDL işlemi tamamlandığında exclusive lock çıkarılır.
  • File and log management locks : Bu locklar çeşitli dosyaları korur. Örneğin, bir internal lock control file’ı korur, böylece bir seferde yalnızca bir işlem değiştirebilir. Başka bir lock, online redo log file kullanımını ve arşivlenmesini koordine eder.
  • Tablespace and undo segment locks : Bu locklar tablespaces ve undo segment lerini korur. Örneğin, bir veritabanına erişen tüm instansların bir tablespace’ın çevrimiçi mi yoksa çevrimdışı mı olduğu konusunda anlaşması gerekir.

Kaynaklar
http://oracleguard.com
http://www.ongoinghelp.com/difference-between-dirty-read-non-repeatable-read-and-phantom-read-in-database/
https://docs.oracle.com/database/121/CNCPT/consist.htm#CNCPT1364

Mustafa Bektaş Tepe
İyi Çalışmalar

840 total views, 9 views today