CodeGym /Kurslar /SQL SELF /PL/pgSQL-də debug və optimizasiya zamanı tipik səhvlərin ...

PL/pgSQL-də debug və optimizasiya zamanı tipik səhvlərin təhlili

SQL SELF
Səviyyə , Dərs
Mövcuddur

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:

  1. Dəyişənləri elan edəndə həmişə default dəyər ver:
   DECLARE
       discount_rate NUMERIC := 0.1; -- Default dəyər
  1. Dəyişənlərin dəyərlərini yoxlamaq üçün RAISE NOTICE istifadə 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:

  1. EXPLAIN ANALYZE istifadə et, sorğunun effektivliyini yoxla:
EXPLAIN ANALYZE SELECT id, total FROM orders WHERE total > 1000;
  1. 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:

  1. Əməliyyatların ardıcıllığını əvvəlcədən düşün və ona riayət et.
  2. Lazım olsa SERIALIZABLE isolation 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

  1. Loglama əlavə et: funksiyanın kritik mərhələlərində RAISE NOTICE istifadə et, icranı izləmək üçün.
  2. Funksiyaları test et: funksiyaları və prosedurları yoxlamaq üçün mütəmadi olaraq test datalarından istifadə et.
  3. Kodun oxunaqlığını saxla: kompleks funksiyaları kiçik alt funksiyalara və prosedurlara böl.
  4. Performansı analiz et: sorğuların effektiv işlədiyinə əmin olmaq üçün EXPLAIN ANALYZE istifadə et.
  5. 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.

1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Funksiyaların optimallaşdırılması
Funksiyaların optimallaşdırılması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION