Kurs
SQL’in Oracle tarafından sağlanan yordamlı dil uzantısı olan PL/SQL, Oracle veritabanlarıyla çalışacaksanız mutlaka bilmeniz gereken bir konudur. Bu; veritabanı yöneticisi, geliştirici ve veri analisti gibi veritabanında karmaşık iş mantıklarını yönetmesi gereken temel roller için de geçerlidir.
Görüşmecilerin adayları üç temel açıdan değerlendirdiğine inanıyorum:
- Kavramsal Anlayış: Temel ilkeler, veri türleri, kontrol yapıları ve istisna yönetimi.
- Pratik Kodlama Becerisi: Verimli saklı yordamlar, fonksiyonlar, tetikleyiciler ve paketler yazma.
- Performans Hususları: Çalışma süresini iyileştirmek, kaynak tüketimini en aza indirmek ve SQL ile PL/SQL arasında aşırı bağlam geçişleri gibi hatalardan kaçınmak için PL/SQL kodunu optimize etme.
Yardımcı olmak için PL/SQL mülakat sorularına dair bir rehber sunuyorum. Temel kavramlarla başlayacak ve toplu işleme, dinamik SQL ve performans ayarlama gibi daha ileri konulara ilerleyeceğim.
Oracle veritabanının temel kavramlarını anlamak isterseniz, Oracle veritabanıyla nasıl etkileşim kuracağınızı ve veritabanının sorguları işlemek için PL/SQL’i nasıl kullandığını öğrenmek açısından çok önemli bir kaynak olan Introduction to Oracle SQL kursumuzu öneririm.
Başlangıç Düzeyi PL/SQL Mülakat Soruları
İlk mülakat aşamasında, görüşmeci temel veritabanı ve PL/SQL kavramlarına dair bilginizi ölçmek için temel sorular sorabilir. Bu soruları ve cevaplarını çalışarak mülakatın ilk aşamasına hazırlanın.
1. PL/SQL nedir?
PL/SQL, Oracle’ın SQL’e yönelik yordamlı uzantısıdır. Veri alma ve işleme odaklı bildirime dayalı SQL’in aksine PL/SQL, geliştiricilerin yordamlı mantık uygulamasına imkân tanır; bu da onu veritabanı içinde karmaşık iş kuralları yazmak için güçlü bir araç yapar. Değişkenleri, döngüleri, koşulluları, istisna yönetimini ve yordamlar, fonksiyonlar ve paketler aracılığıyla modüler programlamayı destekler.
2. Bir PL/SQL bloğunun temel yapısı nedir?
PL/SQL bloğu, PL/SQL’de yürütmenin temel birimidir ve dört ana bölümden oluşur:
-
DECLARE(İsteğe bağlı): Değişkenler, sabitler, imleçler ve kullanıcı tanımlı türlerin tanımlandığı yer. -
BEGIN: SQL sorguları ve yordam ifadelerinin yazıldığı yürütülebilir bölüm. -
EXCEPTION(İsteğe bağlı): Çalışma zamanı hataları ve istisnaları ele alarak hataların zarif şekilde toparlanmasını sağlar. -
END;: Bloğun bittiğini belirtir.
3. Temel PL/SQL veri türleri nelerdir?
PL/SQL, aşağıdaki şekilde kategorize edilen çeşitli veri türlerini destekler:
-
Skaler Türler:
NUMBER,VARCHAR2,DATE,BOOLEANgibi tek değerli türler. -
Bileşik Türler:
RECORD(özel yapılar) veTABLE/VARRAY(diziler) gibi koleksiyonlar. -
Başvuru Türleri: Veritabanı nesnelerine işaretçiler; örneğin dinamik sorgu işlemede
REF CURSOR.
4. PL/SQL’de temel kontrol yapıları nelerdir?
PL/SQL, program akışını yönetmeye yardımcı olan birkaç kontrol yapısı içerir:
-
Döngüler:
LOOP,FOR LOOPveWHILE LOOPgibi yapılar, ifadelerin tekrarlı olarak yürütülmesini sağlar. -
Koşullu İfadeler:
IFveCASEdeyimleri yer alır; koşullara göre farklı kod bloklarını yürütür. DECODE() fonksiyonu da incelenmeye değer başka bir koşul örneğidir.
Orta Düzey PL/SQL Mülakat Soruları
Temel soruları ele aldığımıza göre şimdi bazı orta düzey veri yapısı mülakat sorularına geçelim. Temel bilginiz test edildikten sonra, görüşmeciler PL/SQL kavramlarını uygulama ve kullanma konusundaki teknik yeterliliğinizi ölçmek isteyecektir.
5. Saklı yordamlar ile fonksiyonlar arasındaki fark nedir?
Saklı yordamlar ve fonksiyonlar, her ikisi de yeniden kullanılabilir PL/SQL kod bloklarıdır ancak amaçları oldukça farklıdır.
Saklı yordamlar, değer döndürmeyen işlemleri gerçekleştirmek için kullanılır; veri ekleme, güncelleme veya silme gibi. Bir sonuç döndürmeden veriyi değiştiren veya karmaşık işlemleri yürüten görevlerde kullanılırlar.
Örneğin, aşağıdaki yordam, girilen employee_id’ye sahip çalışanın salary değerini, belirtilen p_increment tutarını ekleyerek günceller; böylece maaş, giriş parametrelerine bağlı olarak dinamik şekilde güncellenir,
CREATE PROCEDURE update_salary(p_emp_id NUMBER, p_increment NUMBER) AS
BEGIN
-- Update the salary of the employee with the given ID
UPDATE employees
SET salary = salary + p_increment
WHERE employee_id = p_emp_id;
END;
Öte yandan fonksiyonlar, işlemleri gerçekleştirdikten sonra bir değer döndürür. Sonuç döndürmesi gereken hesaplamalar veya veri alma işlemleri için uygundurlar.
Aşağıdaki fonksiyon, bir çalışanın maaşını almayı kolaylaştırır; SQL sorgularında veya diğer yordamlar içinde yeniden kullanılabilir.
CREATE FUNCTION get_employee_salary(p_emp_id NUMBER) RETURN NUMBER AS
v_salary NUMBER;
BEGIN
-- Retrieve the salary for the given employee ID
SELECT salary INTO v_salary
FROM employees
WHERE employee_id = p_emp_id;
-- Return the retrieved salary
RETURN v_salary;
END;
6. PL/SQL paketleri nedir?
PL/SQL paketleri, ilgili yordamlar, fonksiyonlar ve değişkenlerden oluşan; kodu daha iyi organize etmek ve yeniden kullanmak için kapsülleyen yapılardır. İki bölümden oluşurlar:
- Paket Tanımı (Specification): Genel öğeleri (yordamlar, fonksiyonlar, değişkenler) bildirir.
- Paket Gövdesi (Body): Tanımda bildirilen yordam ve fonksiyonların uygulama ayrıntılarını içerir.
Örneğin, aşağıdaki sorgu, bir çalışanın maaşını artırmaya yönelik bir yordam ile toplam çalışan sayısını döndüren bir fonksiyon tanımlayan employee_pkg paketini oluşturur; uygulamaları paket gövdesinde sağlanacaktır.
-- Create a package named 'employee_pkg'
CREATE PACKAGE employee_pkg AS
-- Procedure to increase an employee's salary by a percentage
PROCEDURE raise_salary(p_emp_id NUMBER, p_percent NUMBER);
-- Function to return the total number of employees
FUNCTION get_total_employees RETURN NUMBER;
END employee_pkg;
7. PL/SQL tetikleyicileri (trigger) nedir?
Tetikleyiciler, ekleme, güncelleme veya silme gibi belirli veritabanı olaylarına yanıt olarak otomatik çalışan PL/SQL bloklarıdır. İş kurallarını zorlamak için kullanılırlar; ayrıca denetim (auditing) işlemlerinde yaygın biçimde kullanılırlar. Şu şekilde sınıflandırılırlar:
- Satır Düzeyi Tetikleyiciler: Etkilenen her bir satır için bir kez çalışır.
- Deyim Düzeyi Tetikleyiciler: Etkilenen satır sayısından bağımsız olarak her bir SQL deyimi için bir kez çalışır.
Aşağıdaki sorgu, employees tablosunda AFTER UPDATE tetikleyicisi trg_salary_audit oluşturur ve maaş değişikliklerini salary_audit table tablosuna kaydeder; çalışan kimliği, eski ve yeni maaş ile güncelleme zaman damgasını yakalar.
-- Create or replace a trigger 'trg_salary_audit'
CREATE OR REPLACE TRIGGER trg_salary_audit
AFTER UPDATE OF salary ON employees -- Fires after salary updates in 'employees' table
FOR EACH ROW -- Executes for each updated row
BEGIN
-- Inserts old and new salary details into 'salary_audit' table
INSERT INTO salary_audit (employee_id, old_salary, new_salary, change_date)
VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
SQL Tetikleyicileri üzerine hazırladığımız eğitimi inceleyin; mülakat sırasında tetikleyiciler gündeme gelirse hazır olursunuz.
8. PL/SQL’de istisna yönetimi yöntemleri nelerdir?
PL/SQL, kararlılık sağlamak ve çöküşleri önlemek için hata yönetim mekanizmaları sunar. İstisna türleri şunlardır:
-
Ön Tanımlı İstisnalar:
NO_DATA_FOUND,TOO_MANY_ROWSveZERO_DIVIDEgibi yerleşik istisnalar. -
Kullanıcı Tanımlı İstisnalar:
EXCEPTIONile bildirilir veRAISEile tetiklenir.
Örneğin aşağıdaki PL/SQL bloğu, kimliği 100 olan çalışanın maaşını alır; maaş 1000’in altındaysa özel bir istisna oluşturur ve çalışan kaydı bulunmaması ile beklenmeyen istisnalar dahil olası hataları ele alır.
DECLARE
v_salary NUMBER; -- Variable to store the employee's salary
e_low_salary EXCEPTION; -- Custom exception for low salary
BEGIN
-- Retrieve salary of employee with ID 100
SELECT salary INTO v_salary FROM employees WHERE employee_id = 100;
-- Raise exception if salary is below 1000
IF v_salary < 1000 THEN
RAISE e_low_salary;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- Handle case where employee ID is not found
DBMS_OUTPUT.PUT_LINE('Employee not found.');
WHEN e_low_salary THEN -- Handle custom low salary exception
DBMS_OUTPUT.PUT_LINE('Salary is below the allowed threshold.');
WHEN OTHERS THEN -- Handle any other unexpected errors
DBMS_OUTPUT.PUT_LINE('An unexpected error occurred: ' || SQLERRM);
END;
İstisna yönetimi için en iyi uygulamalar şunlardır:
- Olası istisnaları her zaman öngörün.
- Anlamlı hata mesajları kullanın.
- İstisnaları denetim için kaydedin.
- İstisna yönetimi kodunu kısa tutun ve toparlamaya odaklanın.
9. Bir UPDATE ifadesinin çalışıp çalışmadığını nasıl doğrularsınız?
SQL %NOTFOUND özniteliği, UPDATE ifadesinin herhangi bir kaydı değiştirip değiştirmediğini belirlemek için kullanılabilir. Son çalıştırılan SQL deyimi hiçbir satırı etkilemediyse, bu değişken TRUE döndürür.
Örneğin, aşağıdaki sorgu, bölüm 10’daki çalışanların maaşını %10 artırır ve ardından %NOTFOUND özniteliğini kullanarak UPDATE ifadesinin herhangi bir satırı etkileyip etkilemediğini kontrol eder. Hiçbir satır güncellenmediyse "No rows were updated." mesajını yazdırır. Satırlar güncellendiyse, SQL%ROWCOUNT özniteliği ile etkilenen satır sayısını yazdırır.
DECLARE
-- Declare a variable to store the number of rows updated
rows_updated INTEGER;
BEGIN
-- Perform an UPDATE statement on the 'employees' table
UPDATE employees
SET salary = salary * 1.1
WHERE department_id = 10;
-- Check if any rows were updated by using %NOTFOUND
IF SQL%NOTFOUND THEN
-- If no rows were updated, print a message
DBMS_OUTPUT.PUT_LINE('No rows were updated.');
ELSE
-- If rows were updated, print how many rows were affected
rows_updated := SQL%ROWCOUNT; -- Store the number of rows updated
DBMS_OUTPUT.PUT_LINE(rows_updated || ' rows were updated.');
END IF;
END;
/
İleri Düzey PL/SQL Mülakat Soruları
Şimdi, daha fazla deneyim gerektiren kıdemli roller için bazı ileri düzey mülakat sorularını inceleyelim.
10. PL/SQL’de performansı optimize etme yöntemleri nelerdir?
SQL ile PL/SQL arasındaki bağlam geçişlerini en aza indirmek, performansı optimize etmek için kritik önemdedir. Her geçiş bir ek yük oluşturur; özellikle iki ortam arasında sık geçişlerin olduğu durumlarda yürütme sürelerini yavaşlatabilir.
11. Bağlam geçişlerini en aza indirmek için toplu işlemleri nasıl kullanırsınız?
PL/SQL, birden çok satırı tek seferde getirerek veya değiştirerek SQL ile PL/SQL etkileşimini optimize eden toplu işleme teknikleri sağlar.
Örneğin, aşağıdaki PL/SQL bloğu, BULK COLLECT ile bölüm 10’daki tüm çalışanları bir koleksiyona alır ve her bir çalışanın adını yazdırmak için koleksiyonda dolaşır; böylece SQL ile PL/SQL arasındaki bağlam geçişlerini en aza indirerek performansı artırır.
DECLARE
-- Define a table-type collection based on the 'employees' table structure
TYPE emp_table IS TABLE OF employees%ROWTYPE;
v_emps emp_table; -- Declare a variable of this type
BEGIN
-- Bulk fetch employees from department 10 into the collection
SELECT * BULK COLLECT INTO v_emps FROM employees WHERE department_id = 10;
-- Loop through the collection and print employee names
FOR i IN 1..v_emps.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_emps(i).employee_name);
END LOOP;
END;
Ayrıca bu PL/SQL bloğu, FORALL kullanarak 101, 102 ve 103 kimlikli çalışanların maaşlarını %10 artırmak için toplu güncelleme yapar.
DECLARE
-- Define a table-type collection for employee IDs
TYPE t_emp_ids IS TABLE OF employees.employee_id%TYPE;
-- Initialize collection with specific employee IDs
v_emp_ids t_emp_ids := t_emp_ids(101, 102, 103);
BEGIN
-- Bulk update salaries by 10% for specified employee IDs
FORALL i IN 1..v_emp_ids.COUNT
UPDATE employees SET salary = salary * 1.10 WHERE employee_id = v_emp_ids(i);
END;
12. Dinamik SQL ve Ref Cursor’lar (Başvuru İmleçleri) nedir?
Dinamik SQL, SQL ifadelerinin çalışma anında dinamik olarak yürütülmesini sağlar; değişken tablo adları, sütunlar veya sorgu yapılarıyla çalışırken faydalıdır.
Aşağıdaki PL/SQL bloğu, employees tablosundaki satır sayısını dinamik SQL ile sayar ve sonucu yazdırır. Bu yaklaşımı seviyorum; çünkü esneklik sağlar.
DECLARE
v_table_name VARCHAR2(50) := 'employees'; -- Store table name
v_count NUMBER; -- Variable to hold row count
BEGIN
-- Dynamically count rows in the specified table
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || v_table_name INTO v_count;
-- Print the total count
DBMS_OUTPUT.PUT_LINE('Total Employees: ' || v_count);
END;
Ref Cursor’lar, çalışma anında açılabilen, getirilebilen ve kapatılabilen dinamik imleçlerdir; program birimleri arasında sorgu sonuçlarının aktarılmasını sağlar.
Aşağıdaki PL/SQL bloğu, bölüm 20’deki çalışan adlarını almak ve yazdırmak için bir REF CURSOR kullanır. İmleç dinamik olarak açılır, bir döngüyle üzerinden geçilir ve işlemden sonra kapatılır.
DECLARE
-- Define a REF CURSOR type
TYPE emp_ref_cursor IS REF CURSOR;
v_cursor emp_ref_cursor; -- Declare a cursor variable
v_name employees.employee_name%TYPE; -- Variable to store employee name
BEGIN
-- Open the cursor for employees in department 20
OPEN v_cursor FOR SELECT employee_name FROM employees WHERE department_id = 20;
-- Fetch and print employee names in a loop
LOOP
FETCH v_cursor INTO v_name;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_name);
END LOOP;
-- Close the cursor
CLOSE v_cursor;
END;
13. Değişen tablo (mutating table) hatalarını nasıl ele alırsınız?
Değişen tablo hataları, bir tetikleyici tetiklendiği tabloyu değiştirmeye çalıştığında ortaya çıkar. Bileşik tetikleyici (compound trigger), tetikleyici yürütmesini BEFORE, AFTER ve FOR EACH ROW gibi birden fazla aşamaya bölmeye olanak tanıyarak doğrudan değiştirme sorunlarını önler.
Aşağıdaki bileşik tetikleyici, her satır güncellemesinden önce verileri toplayıp deyimden sonra toplu ekleme yaparak salary_audit tablosuna maaş değişikliklerini verimli şekilde kaydeder; bağlam geçişlerini azaltır ve performansı iyileştirir.
CREATE OR REPLACE TRIGGER trg_salary_audit
FOR UPDATE OF salary ON employees -- Trigger fires on salary updates
COMPOUND TRIGGER
-- Declare an associative array to store audit records
TYPE t_salary_audit IS TABLE OF salary_audit%ROWTYPE INDEX BY PLS_INTEGER;
v_audit_data t_salary_audit;
v_idx PLS_INTEGER := 0;
-- Before updating each row, store old and new salary details
BEFORE EACH ROW IS
BEGIN
v_idx := v_idx + 1;
v_audit_data(v_idx).employee_id := :OLD.employee_id;
v_audit_data(v_idx).old_salary := :OLD.salary;
v_audit_data(v_idx).new_salary := :NEW.salary;
v_audit_data(v_idx).change_date := SYSDATE;
END BEFORE EACH ROW;
-- After the statement, insert all audit records in bulk
AFTER STATEMENT IS
BEGIN
FORALL i IN 1..v_idx
INSERT INTO salary_audit VALUES v_audit_data(i);
END AFTER STATEMENT;
END trg_salary_audit;
14. PL/SQL’de aşırı yükleme (overloading) nedir?
Aşırı yükleme, aynı ada sahip ancak farklı parametrelere sahip birden fazla yordam veya fonksiyonun bir pakette tanımlanmasına olanak tanır. Benzer işlemleri gerçekleştirmek için birden fazla yol sunarak kodun okunabilirliğini ve sürdürülebilirliğini artırır.
Aşağıdaki sorguda, paket gövdesi update_salary adlı iki aşırı yüklenmiş yordam uygular: Biri çalışanın maaşını belirtilen miktarda artırır; diğeri ise geçerlilik tarihiyle birlikte yeni maaş belirler ve employees tablosunu buna göre günceller.
-- Create the package specification
CREATE OR REPLACE PACKAGE emp_pkg AS
-- Procedure to increment salary by a specified amount
PROCEDURE update_salary(p_emp_id NUMBER, p_increment NUMBER);
-- Overloaded procedure to set a new salary with an effective date
PROCEDURE update_salary(p_emp_id NUMBER, p_new_salary NUMBER, p_effective_date DATE);
END emp_pkg;
/
-- Create the package body
CREATE OR REPLACE PACKAGE BODY emp_pkg AS
-- Procedure to increment salary by a specified amount
PROCEDURE update_salary(p_emp_id NUMBER, p_increment NUMBER) AS
BEGIN
UPDATE employees
SET salary = salary + p_increment
WHERE employee_id = p_emp_id;
END update_salary;
-- Overloaded procedure to set a new salary with an effective date
PROCEDURE update_salary(p_emp_id NUMBER, p_new_salary NUMBER, p_effective_date DATE) AS
BEGIN
UPDATE employees
SET salary = p_new_salary, last_update = p_effective_date
WHERE employee_id = p_emp_id;
END update_salary;
END emp_pkg;
/
15. PL/SQL’de derleyici yönergeleri ve pragmalar nelerdir?
PL/SQL, kodu optimize etmek ve istisnaları ele almak için derleyici yönergeleri (PRAGMA) sağlar. Yaygın pragmalar şunlardır:
-
PRAGMA EXCEPTION_INIT: Kullanıcı tanımlı bir istisnayı bir Oracle hata koduyla ilişkilendirir. -
PRAGMA SERIALLY_REUSABLE: Paket bellek kullanımını ölçeklenebilirlik için optimize eder.
Aşağıdaki PL/SQL bloğu, -20001 hata koduna eşlenen e_invalid_salary adlı özel istisnayı kullanarak geçersiz maaşla çalışan ekleme durumunu ele alır. İstisna tetiklenirse bir hata mesajı yazdırır.
DECLARE
e_invalid_salary EXCEPTION; -- Declare custom exception for invalid salary
PRAGMA EXCEPTION_INIT(e_invalid_salary, -20001); -- Associate exception with error code -20001
BEGIN
-- Attempt to insert an employee with invalid salary
INSERT INTO employees (employee_id, salary) VALUES (999, -1000);
EXCEPTION
-- Handle the custom exception and print a message
WHEN e_invalid_salary THEN
DBMS_OUTPUT.PUT_LINE('Invalid salary detected!');
END;
16. PL/SQL kodunu izlemek ve hata ayıklamak için farklı yöntemler nelerdir?
PL/SQL, kod performansını izlemek ve hata ayıklamak için çeşitli yerleşik paketler sunar. Yaygın yöntemler arasında yürütme akışını izlemek için DBMS_TRACE, oturum etkinliğini izlemek için DBMS_APPLICATION_INFO ve oturum düzeyinde tanılama bilgileri toplamak için DBMS_SESSION kullanımı bulunur.
Aşağıdaki sorgu önce DBMS_SESSION.set_sql_trace(TRUE) ile SQL izlemeyi etkinleştirir; ardından izleme için DBMS_APPLICATION_INFO.set_client_info() ile istemciye özgü oturum bilgisini ayarlar. PL/SQL bloğu yürütülür ve bir UPDATE işlemini simüle eder. Son olarak, DBMS_SESSION.set_sql_trace(FALSE) ile izleme devre dışı bırakılır.
-- Enable tracing for the current session using DBMS_SESSION
BEGIN
-- Start session-level tracing
DBMS_SESSION.set_sql_trace(TRUE);
END;
/
-- Set application information using DBMS_APPLICATION_INFO
BEGIN
-- Set the application name and action for session monitoring
DBMS_APPLICATION_INFO.set_client_info('Trace Debug Session');
DBMS_APPLICATION_INFO.set_action('Debugging PL/SQL Code');
END;
/
-- Example PL/SQL block that simulates a process for debugging
DECLARE
v_employee_id NUMBER := 100;
BEGIN
-- Example query to fetch employee details
FOR rec IN (SELECT first_name, last_name FROM employees WHERE employee_id = v_employee_id) LOOP
DBMS_OUTPUT.put_line('Employee: ' || rec.first_name || ' ' || rec.last_name);
END LOOP;
-- Simulate some logic that could be traced
IF v_employee_id = 100 THEN
DBMS_OUTPUT.put_line('Employee ID is 100');
END IF;
END;
/
-- Disable tracing after the session is complete
BEGIN
-- Stop session-level tracing
DBMS_SESSION.set_sql_trace(FALSE);
END;
/
Senaryo Tabanlı PL/SQL Mülakat Soruları
Gerçek dünyadaki kurumsal uygulamalarda PL/SQL, karmaşık iş mantığını yönetmek için kullanılır. Görüşmeciler, adayın PL/SQL’i pratik senaryolarda uygulama becerisini sıklıkla değerlendirir. Aşağıda bazı temel zorluklar ve bunları çözme stratejileri yer almaktadır.
Bu sonraki ve son bölüm için, eğer mülakata giriyorsanız, sorulara aşağıdaki şablonu izleyerek nasıl cevap vereceğinizi düşünmenizi öneririm; ancak elbette yanıtınızı sektörünüze göre yeniden konumlandırmaya veya kendi deneyiminizi yansıtacak şekilde uyarlamaya çalışın. Aynı şekilde, bir adayı mülakata alıyorsanız ve nasıl soru soracağınıza ve yanıtın ne kadar kapsamlı olduğunu nasıl değerlendireceğinize dair fikir arıyorsanız, bu bölümün hem sorularınız hem de değerlendirme ölçütleriniz için ilham kaynağı olmasını umuyorum.
17. Yoğun eşzamanlı ortamlarda tetikleyicileri nasıl tasarlarsınız?
Bir çalışanın maaşının günde bir kereden fazla güncellenemeyeceği şeklinde bir iş kuralını zorunlu kılmanız gereken bir senaryo düşünün. Ancak veritabanında yüksek işlem eşzamanlılığı vardır ve basit bir tetikleyici çekişmeye veya performans sorunlarına yol açabilir.
Her güncellemede tetiklenen ve performansı yavaşlatabilen satır düzeyi tetikleyici yerine, aynı gün içinde birden fazla maaş güncellemesini önlemek için bir günlük tablosu ile birlikte deyim düzeyi tetikleyici kullanın.
Örneğin, aşağıdaki tetikleyici, güncellemeye izin vermeden önce salary_update_log tablosunu kontrol ederek bir çalışanın aynı gün içinde birden fazla maaş güncellemesini önler. Maaş bugün zaten güncellendiyse bir hata yükseltilir; aksi halde güncelleme tarihi kaydedilir.
-- Create a table to log the last salary update for each employee
CREATE TABLE salary_update_log (
employee_id NUMBER PRIMARY KEY, -- Employee ID as primary key
last_update DATE -- Date of the last salary update
);
-- Create or replace a compound trigger to prevent multiple salary updates on the same day
CREATE OR REPLACE TRIGGER trg_prevent_multiple_salary_update
FOR UPDATE OF salary ON employees
COMPOUND TRIGGER
-- Declare a variable to store last salary update date per row
TYPE emp_log_type IS TABLE OF DATE INDEX BY PLS_INTEGER;
emp_log emp_log_type;
BEFORE STATEMENT IS
BEGIN
-- Load existing salary update logs into memory for reference
FOR rec IN (SELECT employee_id, last_update FROM salary_update_log) LOOP
emp_log(rec.employee_id) := rec.last_update;
END LOOP;
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
-- Check if an entry exists for this employee
IF emp_log.EXISTS(:NEW.employee_id) THEN
-- Validate if salary was updated today
IF emp_log(:NEW.employee_id) = TRUNC(SYSDATE) THEN
RAISE_APPLICATION_ERROR(-20010, 'Salary can only be updated once per day');
ELSE
-- Update log in memory
emp_log(:NEW.employee_id) := TRUNC(SYSDATE);
END IF;
ELSE
-- Insert a new log entry into memory
emp_log(:NEW.employee_id) := TRUNC(SYSDATE);
END IF;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
-- Apply changes to the log table after all row updates
FOR i IN emp_log.FIRST .. emp_log.LAST LOOP
MERGE INTO salary_update_log l
USING (SELECT i AS employee_id, emp_log(i) AS last_update FROM DUAL) s
ON (l.employee_id = s.employee_id)
WHEN MATCHED THEN
UPDATE SET l.last_update = s.last_update
WHEN NOT MATCHED THEN
INSERT (employee_id, last_update) VALUES (s.employee_id, s.last_update);
END LOOP;
END AFTER STATEMENT;
END trg_prevent_multiple_salary_update;
Yukarıdaki örnek, satır düzeyi kilitlemeyi azaltır ve toplu güncellemeler sırasında işlem çatışmalarını en aza indirir.
18. Güvenilirlik için büyük işlemleri daha küçük parçalara nasıl bölersiniz?
Bir bankacılık sisteminde milyonlarca müşteri hesabının faiz oranlarını toplu güncellemeniz gereken bir senaryo düşünün. Tek bir büyük işlemi yürütmek, tabloların çok uzun süre kilitlenmesine veya geri alma (rollback) hatalarına yol açabilir.
Bu durumda, verileri artımlı olarak işlemek ve çekişmeyi önlemek için COMMIT komutunu partiler halinde kullanan toplu işlemeyi tercih edin.
Aşağıdaki PL/SQL bloğu, BULK COLLECT ile hesap kimliklerini getirir ve sonra faiz oranını %5 artırmak için üzerlerinden geçer. Her 1000 güncellemeden sonra değişiklikleri kaydederek performansı artırır ve kaynak kullanımını azaltır. Son bir commit, kalan güncellemelerin de kaydedilmesini sağlar.
DECLARE
-- Define a collection type for account IDs
TYPE t_accounts IS TABLE OF NUMBER; -- Use NUMBER instead of referencing accounts.account_id
v_account_ids t_accounts; -- Variable to store account IDs
v_batch_size CONSTANT NUMBER := 1000; -- Batch size for commits
BEGIN
-- Bulk collect all account IDs into the collection
SELECT account_id BULK COLLECT INTO v_account_ids FROM accounts;
-- Loop through each account ID to update the interest rate
FOR i IN 1 .. v_account_ids.COUNT LOOP
UPDATE accounts
SET interest_rate = interest_rate * 1.05 -- Increase interest rate by 5%
WHERE account_id = v_account_ids(i);
-- Commit after every 1000 updates
IF MOD(i, v_batch_size) = 0 THEN
COMMIT;
END IF;
END LOOP;
COMMIT; -- Final commit for any remaining updates
END;
/
Bu çözüm, bordro gibi finansal sistemlerde işlem hatalarını önleyerek güvenilirliği sağlar.
19. Sürdürülebilirlik için karmaşık mantığı paketler halinde nasıl organize edersiniz?
Bir perakende şirketinin, bir sipariş işleme sistemi uygulaması gerektiğini düşünün: Stok uygunluğunu kontrol etme, stok ayırma, indirim hesaplama ve işlem geçmişini kaydetme gibi birden çok adım içeriyor.
Ayrı bağımsız yordamlar yazmak yerine bu mantığı yapılandırılmış ve sürdürülebilir bir şekilde organize etmelisiniz. Bu nedenle, ilgili yordam ve fonksiyonları kapsüllemek, kodun yeniden kullanılabilirliğini ve sürdürülebilirliğini artırmak için PL/SQL paketlerini kullanın.
Aşağıdaki paket tanımı, envanteri kontrol etme, stok ayırma, indirim hesaplama ve işlem durumlarını kaydetme gibi sipariş işleme fonksiyon ve yordamlarını tanımlar. Siparişle ilgili görevleri ele almak için modüler bir yaklaşım sunar.
-- Create a package specification for order processing functions and procedures
CREATE PACKAGE order_processing_pkg AS
-- Function to check if enough inventory is available for the product
FUNCTION check_inventory(p_product_id NUMBER, p_quantity NUMBER) RETURN BOOLEAN;
-- Procedure to reserve stock for a specific order
PROCEDURE reserve_stock(p_order_id NUMBER, p_product_id NUMBER, p_quantity NUMBER);
-- Function to calculate discount based on customer and total amount
FUNCTION calculate_discount(p_customer_id NUMBER, p_total_amount NUMBER) RETURN NUMBER;
-- Procedure to log the status of a transaction
PROCEDURE log_transaction(p_order_id NUMBER, p_status VARCHAR2);
END order_processing_pkg;
Ardından, paket tanımında belirlenen fonksiyon ve yordamları uygulamak için aşağıdaki paket gövdesini kullanırız. Envanter uygunluğunu kontrol etme, stok ayırma, indirim hesaplama ve işlem durumlarını kaydetme gibi temel görevleri ele alır; sorunsuz sipariş işleme sağlar.
-- Create the package body implementing the functions and procedures for order processing
CREATE PACKAGE BODY order_processing_pkg AS
-- Function to check if sufficient inventory is available for the product
FUNCTION check_inventory(p_product_id NUMBER, p_quantity NUMBER) RETURN BOOLEAN AS
v_available_qty NUMBER; -- Variable to store available quantity
BEGIN
-- Retrieve the available quantity from inventory
SELECT stock_quantity INTO v_available_qty FROM inventory WHERE product_id = p_product_id;
-- Return true if enough stock is available, otherwise false
RETURN v_available_qty >= p_quantity;
END check_inventory;
-- Procedure to reserve stock for a specific order
PROCEDURE reserve_stock(p_order_id NUMBER, p_product_id NUMBER, p_quantity NUMBER) AS
BEGIN
-- Deduct the ordered quantity from the inventory
UPDATE inventory SET stock_quantity = stock_quantity - p_quantity WHERE product_id = p_product_id;
END reserve_stock;
-- Function to calculate a discount based on the total order amount
FUNCTION calculate_discount(p_customer_id NUMBER, p_total_amount NUMBER) RETURN NUMBER AS
v_discount NUMBER := 0; -- Initialize discount to 0
BEGIN
-- Apply 10% discount if the total amount is greater than 500
IF p_total_amount > 500 THEN
v_discount := p_total_amount * 0.10;
END IF;
-- Return the calculated discount
RETURN v_discount;
END calculate_discount;
-- Procedure to log the transaction status
PROCEDURE log_transaction(p_order_id NUMBER, p_status VARCHAR2) AS
BEGIN
-- Insert a log entry for the order status
INSERT INTO order_log (order_id, status, log_date) VALUES (p_order_id, p_status, SYSDATE);
END log_transaction;
END order_processing_pkg;
20. Yüksek işlem hacimli sistemlerde kilitlenmeleri (deadlock) nasıl yönetirsiniz?
Bir finansal sistemde, ilişkili birden çok tablonun aynı anda sık sık güncellendiği bir senaryo düşünün. İki işlem, birbirlerinin kilitlediği kaynakları beklediğinde kilitlenmeler oluşur ve bu da performans darboğazlarına yol açar.
Bu sorunu çözmek için, işlemler arasında satırları her zaman tutarlı bir sırayla kilitleyin. Ayrıca, süresiz beklemeyi önlemek için NOWAIT veya SKIP LOCKED yan tümcelerini kullanın.
Örneğin, aşağıdaki PL/SQL bloğu, FOR UPDATE NOWAIT yan tümcesini kullanarak accounts tablosunda belirli bir satırı güncelleme için kilitlemeye çalışır; satır başka bir oturum tarafından zaten kilitlendiyse işlem hemen başarısız olur. Kilitledikten sonra işlem durumunu günceller ve değişiklikleri kaydeder. Bir hata oluşursa istisnayı yakalar ve bir hata mesajı yazdırır.
DECLARE
v_balance NUMBER(15,2); -- Declare variable to store the account balance
BEGIN
-- Lock the account row for update to prevent other sessions from modifying it
SELECT balance INTO v_balance FROM accounts
WHERE account_id = 101 FOR UPDATE NOWAIT;
-- Update the transaction status to 'Processed' for all transactions related to this account
UPDATE transactions
SET status = 'Processed'
WHERE account_id = 101 AND status = 'Pending'; -- Update only pending transactions
COMMIT; -- Commit the changes
EXCEPTION
-- Handle errors, such as locking issues or unexpected exceptions
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Transaction failed: ' || SQLERRM);
ROLLBACK; -- Ensure rollback in case of failure
END;
/
Benzer şekilde, bu PL/SQL bloğu bekleyen işlemleri FOR UPDATE SKIP LOCKED ile kilitleyerek işler; böylece diğer oturumlarca kilitlenmiş satırları atlar. Her bir işlemin durumunu ‘Processing’ olarak günceller ve sonunda değişiklikleri kaydeder.
DECLARE
-- Declare a cursor to select pending transactions and lock rows for update
CURSOR c_pending_txns IS
SELECT transaction_id FROM transactions WHERE status = 'Pending' FOR UPDATE SKIP LOCKED; -- Skip locked rows
BEGIN
-- Loop through the pending transactions
FOR txn IN c_pending_txns LOOP
-- Update the status of each transaction to 'Processing'
UPDATE transactions SET status = 'Processing' WHERE transaction_id = txn.transaction_id;
END LOOP;
COMMIT; -- Commit the changes to finalize the transaction updates
END;
Sonuç ve Ek Kaynaklar
Oracle odaklı rollerde işverenler, doğru PL/SQL kodu yazabilen, gerçek hayat zorluklarını ele alabilen ve veritabanı performansını optimize edebilen adaylar arar. PL/SQL ile ilgili kapsamlı bir kılavuz ve en iyi uygulamalar için resmi Oracle dokümantasyonundaki PL/SQL Language Reference’ı incelemenizi öneririm. Oracle Live SQL (Etkileşimli PL/SQL Oyun Alanı), PL/SQL sorgularını çevrimiçi çalıştırmak için Oracle’ın bulut tabanlı platformuna erişim sağlar. Ayrıca Oracle Community’ye katılarak Oracle uzmanları ve geliştiricileriyle etkileşime geçmenizi ve PL/SQL ile ilgili sorulara çözüm bulmak için Stack Overflow forumunu ziyaret etmenizi öneririm.
Yine de, hiçbir şey yapılandırılmış bir öğrenme yolunun yerini tutmaz. Bu nedenle, Introduction to Oracle SQL kursumuzu şiddetle tavsiye ediyorum; bana göre gerçekten uzman olmanın en iyi yolu bu. Ayrıca, veritabanlarıyla çalışma bilginizi ilerletmek isterseniz, ihtiyaçlarınıza uygun DBMS’i seçerek veritabanları oluşturmayı ve yönetmeyi öğreneceğiniz Database Design kursumuzu öneririm. Son olarak, veri mühendisliği ve veri ambarının temellerini öğrenmek için Associate Data Engineer in SQL kariyer yolumuzu deneyin.
Son olarak, adayları mülakata alıyor ve başkalarının yetkinliklerini de artırmak istiyorsanız, DataCamp for Business ekibimizle iletişime geçin. DataCamp, uygulamalı projeler ve özel öğrenme yollarıyla tüm ekipleri geliştirebilir. Bu, işverenler için yetkinlik açıklarını kapatmanın ve ekibin güvenini ve itibarını artırmanın harika bir yoludur; bugün ekibimizle iletişime geçin.
PL SQL SSS
PL/SQL nedir ve SQL’den nasıl ayrılır?
PL/SQL, Oracle tarafından geliştirilen yordamlı bir dildir; kontrol yapıları ve hata yönetimine imkân tanır. SQL ise bildirimseldir ve veri alma/işlemeyi ele alır.
PL/SQL paketi nedir?
Modüler programlama ve yeniden kullanım için ilgili yordamlar, fonksiyonlar, değişkenler ve imleçlerden oluşan bir koleksiyon.
Yordam ile fonksiyon arasındaki fark nedir?
Yordamlar değer döndürmeyen bir eylem gerçekleştirir; fonksiyonlar ise sorgularda kullanılabilecek bir değer döndürür.
PL/SQL’de tetikleyiciler nedir?
INSERT, UPDATE, DELETE işlemlerinden önce veya sonra yürütülen otomatik eylemler.
PL/SQL’de toplu işleme (bulk processing) nedir?
BULK COLLECT, FORALL gibi toplu işlemler, büyük veri kümeleriyle çalışırken PL/SQL ve SQL motorları arasındaki bağlam geçişlerini azaltarak performansı artırır.

