PL/SQL
Best Practıces
Emrah METE
Senior ETL Developer
Board Member of TROUG
Emrah METE
- Yıldız Teknik Üniversitesi – Bilgisayar Mühendisliği
- İş Deneyimi
- Software Developement Specialist @Turkcell Teknoloji
- Senior BI Consultant @i2i-Systems
- Senior BI Specialist @HititCs
- Senior ETL Developer @Turkcell Teknoloji
- Teknik Uzmanlık
- 5+ Oracle SQL, Oracle PL/SQL, ETL, DWH, BI
- Kurucu Üye ve Yönetim Kurulu Üyesi @TROUG
- Moderatör @OracleTurk
- Blogger
- https://emrahmete.wordpress.com/ (Türkçe)
- https://emrahmeteen.wordpress.com/ (İngilizce)
- Oracle Certified SQL Expert
- Oracle Database Developer Choice Awards 2015, SQL Category Winner!!!
- Oracle ACE
https://emrahmete.wordpress.com/about/
1
Don't
Hard Codıng
VARCHAR2(N) Declaration
Business Rules and Formulas
SQL STATEMENTS
APPLICATION
T1
T2
T3
T4
DML
DML
OPTIMIZE MAINTAIN DEBUG
SOLUTION: SQL AS A SERVICE
APPLICATION
DATA LAYER
T3 T3 T3 T3 T3
APPLICATION
DATA LAYER
T3
OPTIMIZE MAINTAIN DEBUG WRITE CODE
FASTER
Fix Bugs
Faster
REUSED
CODE
SOLUTION: SQL AS A SERVICE
2
Don’t
row by row
processıng
ROW BY ROW PROCESSING
HOW IT WORKS
SOLUTION: BULK PROCESSING
SOLUTION: BULK PROCESSING
SOLUTION: BULK PROCESSING : HOW IT WORKS
BULK COLLECT LIMITATIONS
BULK PROCESSING
DATASET 1
ARRAY
TRANSFORMATION
TABLE
BULK COLLECT FORALL
3
memory management
- PACKAGE LEVEL PARAMETERS
- BULK COLLECT WITH LIMIT CLAUSE
- BULK COLLECT WITH VARRAYS
- USING PARALLEL PIPELINED FUNCTIONS
- USING NOCOPY HINT
MEMORY MANAGEMENT
USING NOCOPY
- IN => pass by reference
- OUT, IN OUT => default pass by value
- NOCOPY => pass by reference
+ Memory Consumption
+ Improve Performance
- Do not trust (in Exception State)
4
Data cachıng
- Great technique for improving application performance
- SGA is an huge and sophisticted for the database instance.
- Also We have three other caches that we can use in PL/SQL code
- Deterministic Functions
- PGA Caching
- Function Result Cache
DATA CACHING
- PL/SQL Functions declared as Deterministic
- Caching using PGA
- Used most effectively with collections
- Accessing PGA more efficient than SGA
- Function Result Cache (Oracle DB 11g)
DATA CACHING
FUNCTION RESULT CACHE
DETERMINISTIC
LiveSQL!!!
https://livesql.oracle.com
REFERENCES
- Oracle PL/SQL Best Practices
- Oracle PL/SQL Programming
- http://www.oracle.com/technetwork/issue-archive/2010/10-sep/o57plsql-088600.html
- http://orasql.org/category/oracle/deterministic-functions/
- Practically Perfect PL/SQL with Steven Feuerstein
- https://www.youtube.com/watch?v=0PSrI7iT1AQ
- https://www.youtube.com/watch?v=8NoOATGP9v8
- https://www.youtube.com/watch?v=VBkRTXz5pug
- https://www.youtube.com/watch?v=D7H1VKMiqj8
- https://www.youtube.com/watch?v=lxLTXcY3e80
- https://www.youtube.com/watch?v=EoyRxPxU26U
thanks!
Any questions?
@emrahmete (twitter)
emrahmete@gmail.com
https://emrahmete.wordpress.com

Oracle PL/SQL Best Practices

Editor's Notes

  • #5 PL/SQL kodu yazarken sık kullandığımız değişken tanımlama metodu varchar2(N) şeklindedir. Bu şekilde değişken tanımlamanın belirli handikapları vardır ve bu handikaplar gün sonunda kodumuzun canlı ortamda hata almasına sebebiyet verebilmektedir. Örneğin PL/SQL kodumuzda X tablosundaki isim kolonunu bir değişkende tutup daha sonra kullanalım. İsim kolonumuzun veri tabanındaki tanımı varchar2(25) şeklinde olsun; Yazdığım PL/SQL kodunda da bu alanı hard coded bir şekilde varchar2(25) olarak kod bloğumu yazdığım durumda, X tablosundaki isim kolonun veri tipi/boyutu değişmediği sürece yazdığım kod parçası doğru çalışmaya devam edecek ancak ne zaman bu tablodaki bu kolonumun veri tipini/veri boyutunu değiştirdiğimde yazdığım PL/SQL kod bloğu çalışma zamanı hataları alacak. Bu hatayı gidermek istediğimde ise başka bir problem ile karşılaşacağım. İlgili alanı bu şekilde hard coded tanımladığım envanterimdeki tüm PL/SQL kodları içerisinde arayıp tek tek manuel değiştirmek zorundayım. Buda oldukça maliyetli bir işlem. Bu durumu engellemenin yolu ise bu şekilde değişken kullanımlarına ihtiyaç duyduğum her yerde %TYPE operatörü kullanarak alanların veri tipi veya veri boyutlarının değişme risklerine karşı PL/SQL kodlarımızın hata almasının önünde geçmek olmalı. Dorğudan bir kolonu adreslemeyen değişen ihtiyaçlarımız için ise paket seviyesinde SUBTYPE yaratıp ilerlemek yine PL/SQL kodlarımızın veri tipi kaynaklı hata almalarını minimize edecektir.
  • #6 PL/SQL kodları içine bir işi gerçekleştiren kural veya formülü doğrudan yazmak sıkça yapılan hatalar arasında. Bu tarz formüllerin ihtiyaç duyulan her yerde hard coded bir şekilde yazılması hatalı formüllerin veya iş kurallarının üretilmesine neden olabilir. Buna ek olarak formülde yapılacak bir değişiklik durumunda bu formülün hard coded yazıldığı her yerde tek tek manuel bulunup değiştirilmesi gerekmekte. Bu iş hem çok maliyetli hemde doğru bir şekilde arama işlemenin yapılmadığı durumda yanlış çalışan kod paraçaları anlamına gelecektir. Bu ve benzeri hataların önüne geçmek için sık kullanılan formülleri veya iş kurallarını ortak bir paket içerisinde farkılı procedure veya fonksiyonlar ile gerçekeleyip, kullanılması gereken yerlerde bu fonksiyon veya prosedürleri çağırarak kullanmak daha doğru ve hatalardan uzak bir kullanım şekli olacaktır. Böylelikle formülde yada iş kuralında bir değişiklik gerektiğinde sadece ilgili fonksiyon veya prosedürü değiştirerek iş tek bir değişiklik ile hatası tamamlanabilir.
  • #7 PL/SQL kod blokları yazılırken en sık yapılan kullanım hatalarından biride kod bloğu içinde çok sık hard coded SQL cümleleri yazmak. Kod bloklarında hard coded SQL yazmak çeşitli zorlukları’da beraberinde getirecektir. Bunlar; Optimize: İlgili SQL cümlesi iyileştirilmek edilmek istendiğinde, ilgili cümlenin geçtiği tüm kodlardaki etkinin doğru bir şekilde incelenip ona göre optimizasyon işleminin yapılması gerekmekte. Bu durum bu işlemin çok uzamasına ve zorlaşmasına neden olabilir. Maintain: İlgil SQL’de yapılacak herhangi bir değişikliğin kullanıldığı heryerde yapılması gerekmekte. Bu bağlamda kodun bakımı oldukça zorlaşacak. Debug: Debug yapılmak istendiğinde kodun yazıldığı heryerde debug işleminin yapılması gerekmekte.
  • #8 Hardcoded SQL yazımının yarattığı handikapların önüne geçmek için, şekildeki gibi bir yaklaşım uygulanarak SQL cümleleri, yazılan PL/SQL kodlarında bir servis şeklinde çağırılmalıdır. Bu yöntem ile çağıralacak SQL kodları merkezi bir paket içerisinde fonksiyon veya prosedür yazılarak, ihtiyaç duyulan yerlerde çağırılması sağlanarak belirli avantajlar sağlanacaktır. Bunlar; Kodun Optimzasyonunun daha kolay ve hızlı yapılması. , Kodun bakımının kolaylaşması., Olası bir değişikliğin Debug edilmesinin kolaylaşarak hızlanması, Kod tek bir yerde yazılacağı için daha hızlı kod geliştirilmesi, Bug onarımlarının tek bir yerden daha hızlı yapılması, Bir kez yazılan kodun tekrar tekrar kullanılması,
  • #9 Örnek bir SQL servisi. Bu servis ile EMPLOYEES tablosuna insert, update ve delete gibi sık yapılması muhtemel DML operasyonlarının kodları yazılarak bir servis haline getirilmiştir.
  • #11 PL/SQL kod bloklarında en sık kullandığımız yapılardan biride CURSOR ile bir veri gurubunu alıp satır satır işleme tabii tutmak. İlk bakışta bir performans problemi yokmuş gibi gözükse de bu durumun performansı negatif etkileyen önemli etkileri vardır. Bu etkiyi daha ayrıntılı açıklayabilmek adına ilk etapta bu mekanizmanın nasıl çalıştığını anlamak faydalı olacaktır.
  • #12 Oracle veritabanı kodlarımızı execute edebilmek için iki farklı engine sahip. Bunlar; PL/SQL Runtine Engine SQL Engine Yazdığımız PL/SQL kod bloklarında kodumuzun PL/SQL ile ilgili kısımları «PL/SQL Runtine Engine»’de SQL ile ilgili kısımları «SQL Engine»’de execute edilmekte ancak bu iş birbirinden bağımsız gerçekleşmemekte. Örneğin bir döngü içerisinde yapılan bir update işleminde döngü ile ilgili işlemler PL/SQL Runtime Engine içerisinde hesaplanıp, döngünün içerisindeki update cümlesine ilgili parametre geçirilip yeni bir SQL oluşturulmakta. Daha sonra bu oluşan SQL, SQL Engine gönderilip execute edilmesi sağlanıyor. (PL/SQL Runtime Engine ile SQL Engine arasındaki geçişlere Context Switching adı verilmekte. ) Bu işlem sonrasında bir sonuç oluşuyorsa, ilgili sonuç PL/SQL Runtime Engine geri döndürülüyor ve döngü bir sonraki iterasyon ile devam ediyor. Döngü sonlanana kadar bu işlem sırası ile gerçekleştiriliyor. Bu işlemler esnasında her adımda bir Context Switching söz konusu. Context her iki engine arasında her değiştiğinde belirli bir miktar süre kaybediliyor yapılan geçiş sebebi ile. Context Switch sayısının artması haliyle büyük performans kayıplarına sebebiyet vermekte.
  • #13 Context Switching maliyetini düşürmek için uygulanacak çözümlerden biri Bulk Processing. Bu yöntem ile işlenecek veri kümesi BULK COLLECT INTO söz deyimi ile bir kerede diziye atılıp daha sonra FORALL söz deyimi ile bu array minimum context switch ile veritabanına gönderiliyor ve işlemlerin daha hızlı yapılması sağlanıyor.
  • #14 Örnekte de görüldüğü üzere BULK PROCESSING standart kullandığımız yönteme göre neredeyse 2 kat daha hızlı çalıştı. Çalışma hızı performansı sistemimize ve işleyecek datanın büyüklüğüne göre pozitif olarak değişkenlik gösterebilir.
  • #15 Şekilden de anlaşılacağı üzere PL/SQL bloğunda üretilen DML’ler SQL Engine tek tek değil toplu bir şekilde gönderilmekte ve bu sayede daha az context switching yapılmakta. Context Switching in az yapılması uygulamamızın çalışma hızını pozitif yönde etkilemekte.
  • #16 BULK COLLECT’in kullanıldığı uygulamalarda, uygulamamızın memory tüketimine dikkat etmeliyiz. Eğer işleyeceğimiz veri miktarı büyükse, uygulamamızın memory tüketimini kontrol altına almak için LIMIT söz deyimini kullanmamız sistemin genel kaynak kullanımını pozitif yönde etkileyecektir.
  • #17 Bulk Processing kabaca şekildeki gibi çalışmaktadır.
  • #19 Yazdığımız kodlarda en çok dikkat etmemiz gereken konulardan biride memory yönetimi. Yazdığımız kodlar ve işleyeceğimiz veriler için Oracle tarafından arka planda belirli hafıza alanları tahsis edilir ve bu alanlar sistem ayakta olduğu sürece kullanılır. Bu memory alanları sınırsız olmadığından bu alanların efektif bir şekilde kullanımını yazdığımız kodlar ile belirli seviyede sağlamamız mümkün.
  • #20 Yazdığımız paket içerisinde tanımladığımız değişkenleri optimize etmek BULK COLLECT ile LIMIT cümlesi kullanmak BULK COLLECT ile VARRAY kullanımına dikkat etmek PARALLEL PIPELINED Fonksiyonların kullanımını arttırmak Fonksiyon veya Prosedürlere parametre aktarımlarında NOCOPY hinti kullanmak Yukarıda sıralamış olduğumuz hususlara dikkat etmemiz uygulamalarımızın daha etkin memory kullanmasına olanak sağlayacaktır.
  • #21 NOCOPY hinti verinin fonksiyon veya prosedürlere pass by reference mantığı ile taşınmasını sağlar. Transfer edilen parametre memory de başka bir alana kopyalanmadığı içinde yazdığımız kod bloğunun tükettiği memory miktarı transfer edeceğimiz parametrenin boyutuna bağlı olarak azalmakta ve genel performansımızı iyileştirmektedir. NOCOPY hinti kullanırken dikkat etmemiz gereken nokta, herhangi bir exception durumunda memoryde değişikliğe uğrattığımız parametrenin orijinal halini kaybetme riskimiz olacaktır. Bu riski göz önünde bulundurarak geliştirmelerimizi yapmalıyız.
  • #23 Veriyi cachleme yazdığımız programların daha performanslı çalışmasını etkileyen önemli parametrelerin başında gelmektedir. Oracle’ında bu bağlamda bize sunduğu bazı alt yapılar mevcuttur. Bu cacheleme alt yapılarını kullanarak performansı daha iyi olan etkin programlar geliştirebilmekteyiz. Veriyi cachlemek için Oracle bize bazı opsiyonlar sunmaktadır bu opsiyonlardan bazıları aşağıda listelenmiştir. Deterministic Functions PGA Caching Function Result Cache Yukarıda listelenmiş tekniklerin etkin kullanımı ile uygulamalarımızın veriye erişim sürelerini kısaltarak performans anlamında yüksek kazançlar elde edebilmekteyiz.
  • #24 Deterministic PL/SQL Functions: (Oracle 8i’den beri mevcut)Eğer deterministic yaratılmış bir fonksyion aynı parametre ile ikinci kez çağırılırsa, optimizer tarafından fonksyion ikinci kez çalıştırılmaz sonuç daha önce o değer için hesaplandığından dolayı otomatik olarak cache den getirilir. Böylelikle aynı parametreler için tekrar tekrar fonskyon çağırımı yapılmaz ve performans kazancı elde edilir. Caching using PGA: Program Global Area’ya erişmek System Global Area’ya erişmekten daha kolaydır. Dolayısıyla bu alanı efektif olarak kullanmak veri erişim sürelerini kısaltma bazında pozitif sonuçlar doğuracaktır. Özellikle collectionları bu bölge içerisinde tanımlayıp kullanmak erişim performansımızı arttıracaktır. Function Result Cache: (Oracle 11g ile gelen bir özellik) Function Result Cache aynı parametre ile çağırılan fonskyon için üretilen sonucu cacheler ve tekrar aynı parametre ile fonksyon çağırıldığında sonucu cacheden okur ve fonskyonu çalıştırmaz. RESULT_CACHE ile yaratılan fonksyonlar ile üretilen sonuclar tüm sessionların erişebildiği bir noktada tutularak, farklı sessionlar tarafından da sonucun kullanılmasına olanak sağlamasıdır.
  • #25 Function Result Cache: Function Result Cache aynı parametre ile çağırılan fonskyon için üretilen sonucu cacheler ve tekrar aynı parametre ile fonksyon çağırıldığında sonucu cacheden okur ve fonskyonu çalıştırmaz. Deterministic fonksiyonlardan farkı, üretilen sonucun tüm sessionların erişebildiği bir noktada tutularak, farklı sessionlar tarafından da sonucun kullanılmasına olanak sağlamasıdır. RESULT_CACHE cümlesi optimizer’a parametre bazlı sonuçların bu fonksyon için saklanması gerektiğini söyler. Sonuçlar cachelendiği için aynı parametre ile tekrar fonksyon çağırıldığında optimizer sonucu cachledigi anlar ve sonucu cacheden okur. RELIES_ON cümlesi ise fonksyonun kullandığı tablodaki olası data değişiminin algılanıp (cachedeki sonucun değişimine neden olacak durumlarda) cache deki sonucu invalid hale getirip aynı parametre ile tekrar çağırıldığında fonksyonun yeniden çalışmasını sağlamak olacaktır.
  • #26 Deterministic PL/SQL Functions: Eğer deterministic yaratılmış bir fonksyion aynı parametre ile ikinci kez çağırılırsa, optimizer tarafından fonksyion ikinci kez çalıştırılmaz sonuç daha önce o değer için hesaplandığından dolayı otomatik olarak cache den getirilir. Böylelikle aynı parametreler için tekrar tekrar fonskyon çağırımı yapılmaz ve performans kazancı elde edilir.