Bu gün, PL/pgSQL üzrə bu epik səyahəti yekunlaşdırmaq üçün, debug və optimizasiya zamanı səni pusquda gözləyən ən yayılmış səhvləri müzakirə edəcəyik. Bu səhvləri bilmək sənə gələcəkdə problemlərdən qaçmağa və bug-larla daha effektiv mübarizə aparmağa kömək edəcək.
Debug və optimizasiya zamanı tipik səhvlər
1. Dəyişənlərin səhv istifadəsi
PL/pgSQL-də funksiyaları yazanda və debug edəndə ən çox rast gəlinən səhvlərdən biri dəyişənlərin düzgün elan edilməməsi və ya istifadəsidir. Məsələn, dəyişənin tipini açıq göstərməyi unutsan və ya parametrlərlə ötürülən dəyərlərdə çaşsan. Gəlin, bu praktiki olaraq necə görünə bilər baxaq:
CREATE OR REPLACE FUNCTION calculate_discount(order_total NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
discount_rate NUMERIC;
BEGIN
-- Ups! discount_rate dəyişənini initialize etməyi unutmuşam
RETURN order_total * discount_rate;
END;
$$ LANGUAGE plpgsql;
Bu funksiyanı çağıranda, NULL ilə hesablama aparıldığı üçün error alacaqsan, çünki discount_rate dəyişəni ilkin olaraq initialize olunmayıb.
Necə qarşısını almaq olar:
- Dəyişənləri elan edəndə həmişə default dəyər ver:
DECLARE
discount_rate NUMERIC := 0.1; -- Default dəyər
- Dəyişənlərin dəyərlərini yoxlamaq üçün
RAISE NOTICEistifadə et, əmin ol ki, gözlədiyin dəyərlərdir:
RAISE NOTICE 'discount_rate dəyəri: %', discount_rate;
2. Error loglamanın olmaması
Başqa bir yayılmış problem — loglama mexanizminin olmamasıdır. Nəsə düz getməyəndə, funksiyanın icrasını loglamırsansa, bu, qaranlıq otaqda qara pişik axtarmaq kimidir, xüsusən də hələ bilmiriksə orda pişik var ya yox.
Loglamasız funksiya nümunəsi:
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS VOID AS $$
BEGIN
-- Sifarişin işlənməsi üçün bir az qarışıq məntiq
UPDATE orders SET status = 'processed' WHERE id = order_id;
END;
$$ LANGUAGE plpgsql;
Bəs order_id səhv ötürülüb? Bəs orders cədvəlində belə bir qeyd yoxdur?
Necə qarşısını almaq olar: Kritik addımları loglamaq üçün RAISE NOTICE və ya RAISE EXCEPTION əlavə et:
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS VOID AS $$
BEGIN
-- Giriş datalarını loglayırıq
RAISE NOTICE 'ID % ilə sifariş işlənir', order_id;
-- Qarışıq işləmə məntiqi
UPDATE orders SET status = 'processed' WHERE id = order_id;
-- Nəticəni loglayırıq
RAISE NOTICE 'ID % üçün sifariş statusu yeniləndi', order_id;
END;
$$ LANGUAGE plpgsql;
İndi errorun harada baş verdiyini asanlıqla izləyə biləcəksən, çünki mesajlar çıxacaq.
3. Sorğuların performansını nəzərə almamaq
Bu, hər bir database developer-in əsas düşmənlərindən biridir. Məsələn, sən elə bir funksiya yazırsan ki, hər şey qaydasındadır, amma çox yavaş işləyir. Yavaş sorğuların əsas səbəblərindən biri — indekslərin olmaması və ya query plan-ın səmərəsiz olmasıdır.
Yavaş sorğu nümunəsi:
CREATE OR REPLACE FUNCTION get_large_orders()
RETURNS TABLE(order_id INT, total NUMERIC) AS $$
BEGIN
RETURN QUERY
SELECT id, total FROM orders WHERE total > 1000;
END;
$$ LANGUAGE plpgsql;
Əgər orders cədvəlində total sütunu indekslənməyibsə, sorğu bütün cədvəli scan edəcək və bu, çox səmərəsizdir.
Necə qarşısını almaq olar:
EXPLAIN ANALYZEistifadə et, sorğunun effektivliyini yoxla:
EXPLAIN ANALYZE SELECT id, total FROM orders WHERE total > 1000;
- Tez-tez istifadə olunan sütunlara indeks əlavə et:
CREATE INDEX idx_orders_total ON orders(total);
4. Transaction isolation səviyyəsinin səhv seçilməsi
Çətin prosedurlar icra edəndə bəzən transaction isolation səviyyəsini düzgün başa düşməməkdən errorlar yaranır. Məsələn, iki transaction eyni anda eyni qeydi update etməyə çalışanda deadlock baş verə bilər.
Potensial deadlock nümunəsi:
BEGIN;
UPDATE orders SET status = 'processed' WHERE id = 1;
-- Başqa transaction-un bloklanmasını gözləyir
UPDATE inventory SET stock = stock - 1 WHERE product_id = 100;
COMMIT;
Başqa transaction bu əməliyyatları fərqli ardıcıllıqla etsə, qarşılıqlı bloklanma (deadlock) alacaqsan.
Necə qarşısını almaq olar:
- Əməliyyatların ardıcıllığını əvvəlcədən düşün və ona riayət et.
- Lazım olsa
SERIALIZABLEisolation səviyyəsindən istifadə et.
5. Error handling-in olmaması
Error handling təkcə yaxşı practice deyil, həm də kodunun stabil işləməsi üçün vacibdir. Məsələn, aşağıdakı kodda mümkün errorların qarşısı alınmayıb:
CREATE OR REPLACE FUNCTION add_order(order_id INT)
RETURNS VOID AS $$
BEGIN
INSERT INTO orders (id, status) VALUES (order_id, 'new');
END;
$$ LANGUAGE plpgsql;
Əgər order_id artıq varsa, duplicate key value violates unique constraint erroru alacaqsan.
Necə qarşısını almaq olar: Exception handling bloklarından istifadə et:
CREATE OR REPLACE FUNCTION add_order(order_id INT)
RETURNS VOID AS $$
BEGIN
INSERT INTO orders (id, status) VALUES (order_id, 'new');
EXCEPTION WHEN unique_violation THEN
RAISE NOTICE 'ID % olan sifariş artıq mövcuddur!', order_id;
END;
$$ LANGUAGE plpgsql;
Səhv nümunələri və onların düzəldilməsi
Səhv 1: İndeksin olmaması səbəbindən sorğular yavaş işləyir
Situasiya: Səndə bir sorğu var, cədvəli sütuna görə filterləyir, amma o sütunda indeks yoxdur.
Düzəliş: Müvafiq sütun üçün indeks yarat.
Səhv 2: Funksiyanın məntiqi qarışıqdır və debug etmək çətindir
Situasiya: Funksiya çoxlu məntiq ehtiva edir və alt funksiyalara bölünməyib.
Düzəliş: Çətin funksiyanı kiçik alt funksiyalara böl. Bu, oxunaqlılığı artıracaq və debug-u asanlaşdıracaq.
Səhv 3: RAISE EXCEPTION-dan səhv istifadə
Situasiya: RAISE EXCEPTION bütün errorlar üçün istifadə olunur, hətta önəmsizlər üçün də.
Düzəliş: İnformasiya mesajları üçün RAISE NOTICE, yalnız kritik hallarda RAISE EXCEPTION istifadə et.
RAISE NOTICE 'Hər şey qaydasındadır — funksiyanın cari mərhələsi bitdi.';
RAISE EXCEPTION 'Nəsə pozulub! Giriş parametrlərinə diqqət yetir.';
Səhvlərin qarşısını almaq üçün tövsiyələr
- Loglama əlavə et: funksiyanın kritik mərhələlərində
RAISE NOTICEistifadə et, icranı izləmək üçün. - Funksiyaları test et: funksiyaları və prosedurları yoxlamaq üçün mütəmadi olaraq test datalarından istifadə et.
- Kodun oxunaqlığını saxla: kompleks funksiyaları kiçik alt funksiyalara və prosedurlara böl.
- Performansı analiz et: sorğuların effektiv işlədiyinə əmin olmaq üçün
EXPLAIN ANALYZEistifadə et. - Gözlənilməz hallara hazır ol: error handling üçün həmişə exception blokları əlavə et.
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION 'Gözlənilməz error baş verdi: %', SQLERRM;
Bu, sənə errorlarla rahat işləməyə və gələcəkdə onların qarşısını almağa kömək edəcək.
GO TO FULL VERSION