Əgər nə vaxtsa elə bir vəziyyətlə qarşılaşmısansa ki, kütləvi məlumat yeniləməsində hər bir sətir üçün ayrıca əməliyyat aparmaq və ya sadəcə bütün cədvəl üçün bir dəfə nəsə etmək lazım olubsa, yəqin ki, belə bir sual yaranıb: bunu necə düzgün həyata keçirim? PostgreSQL iki variant təklif edir: sətir səviyyəsində triggerlər və əməliyyat səviyyəsində triggerlər. Hansı yanaşmanı nə vaxt istifadə etməyi bilmək, verilənlər bazasının düzgün dizaynı, performansın optimallaşdırılması və səhvlərdən qaçmaq üçün vacibdir. Gəlin bunu aydınlaşdıraq!
Sətir səviyyəsində triggerlər (FOR EACH ROW) hər bir sətir üçün INSERT, UPDATE və ya DELETE əməliyyatı zamanı işə düşür. Yəni, əgər SQL sorğusu 100 sətri əhatə edirsə, trigger 100 dəfə işləyəcək.
Bunları nə vaxt istifadə etməli?
Sətir səviyyəsində triggerlər faydalıdır, əgər hər dəyişən sətri ayrıca emal etmək lazımdırsa. Məsələn:
- Hər bir sətirdəki dəyişikliklərin logunu aparmaq.
- Hər bir sətir üçün əlaqəli məlumatları avtomatik yeniləmək.
Nümunə: hər bir sətir üçün dəyişikliklərin logunu aparmaq
Tutaq ki, bizdə tələbələrin cədvəli var:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Biz istəyirik ki, bu cədvəldə yenilənən hər bir sətri ayrıca students_log cədvəlinə log edək:
CREATE TABLE students_log (
log_id SERIAL PRIMARY KEY,
student_id INT,
old_name VARCHAR(100),
new_name VARCHAR(100),
changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Dəyişiklikləri log etmək üçün funksiya:
CREATE OR REPLACE FUNCTION log_student_update()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO students_log(student_id, old_name, new_name, changed_at)
VALUES (OLD.id, OLD.name, NEW.name, CURRENT_TIMESTAMP);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
FOR EACH ROW triggerinin yaradılması:
CREATE TRIGGER student_update_logger
AFTER UPDATE ON students
FOR EACH ROW
EXECUTE FUNCTION log_student_update();
Test:
UPDATE students
SET name = 'İvan İvanov'
WHERE id = 1;
Bu sorğunu icra etdikdən sonra students_log cədvəlində dəyişiklik detalları ilə bir qeyd yaranacaq.
Əməliyyat səviyyəsində triggerlər (FOR EACH STATEMENT)
Əməliyyat səviyyəsində triggerlər (FOR EACH STATEMENT) yalnız bir dəfə bütün SQL sorğusu üçün işləyir, fərq etməz neçə sətir təsirlənir. Əgər sorğu 100 sətri yeniləyirsə, trigger cəmi bir dəfə işləyəcək.
Əməliyyat səviyyəsində triggerlər faydalıdır, əgər sənə lazım olsa:
- Bütün əməliyyat üçün yalnız bir dəfə nəsə etmək.
- Cədvəl üzrə ümumi məlumatlarla işləmək və ya hesablama aparmaq.
Nümunə: dəyişiklik sayğacının yenilənməsi
Tutaq ki, bizdə students cədvəli üçün dəyişiklik sayğacı cədvəli var:
CREATE TABLE students_changes_log (
total_changes INT DEFAULT 0
);
INSERT INTO students_changes_log(total_changes) VALUES (0);
Biz istəyirik ki, students cədvəlində hər UPDATE əməliyyatı baş verəndə bu sayğac bir vahid artsın.
Sayğacı yeniləmək üçün funksiya:
CREATE OR REPLACE FUNCTION increment_changes_counter()
RETURNS TRIGGER AS $$
BEGIN
UPDATE students_changes_log
SET total_changes = total_changes + 1;
RETURN NULL; -- Əməliyyat səviyyəsində trigger sətir qaytarmır
END;
$$ LANGUAGE plpgsql;
FOR EACH STATEMENT triggerinin yaradılması:
CREATE TRIGGER update_changes_counter
AFTER UPDATE ON students
FOR EACH STATEMENT
EXECUTE FUNCTION increment_changes_counter();
Test:
UPDATE students
SET age = age + 1
WHERE age < 20;
Sorğu icra olunduqdan sonra trigger yalnız bir dəfə işləyəcək və dəyişiklik sayğacı bir vahid artacaq.
FOR EACH ROW və FOR EACH STATEMENT müqayisəsi
| Kriteriya | FOR EACH ROW | FOR EACH STATEMENT |
|---|---|---|
| İcra səviyyəsi | Təsirlənən hər bir sətir üçün | Bütün əməliyyat üçün bir dəfə |
| Çağırılma tezliyi | Hər sətir üçün bir dəfə | Hər SQL sorğusu üçün bir dəfə |
| Tapşırıqlar | Ayrı-ayrı dəyişikliklərin logu, sətirlərin emalı | Aqreqasiya, metainformasiyanın yenilənməsi |
| Nümunə | Hər bir sətir üçün dəyişikliklərin logu | Dəyişiklik sayğacının yenilənməsi |
| Performans | Kütləvi əməliyyatlarda daha çox resurs tələb edir | Kütləvi əməliyyatlar üçün daha az resurs tələb edir |
FOR EACH ROW və FOR EACH STATEMENT nə vaxt istifadə etməli?
FOR EACH ROW istifadə et:
- Triggerin hər bir sətir üçün işləməsini istəyirsənsə.
- İcra məntiqi konkret sətir dəyişikliklərinə bağlıdırsa.
- Hər bir sətir üçün
OLDvəNEWməlumatlarına ehtiyac varsa.
Nümunə: Cədvəldə dəyişikliklərin logu və ya əlaqəli qeydlərin avtomatik yaradılması.
FOR EACH STATEMENT istifadə et:
- Bütün əməliyyat üçün yalnız bir dəfə nəsə etmək istəyirsənsə.
- Trigger məntiqi konkret sətir dəyişikliklərindən asılı deyilsə.
- Performans kritikdirsə və triggerin kütləvi çağırılması arzuolunmazdırsa.
Nümunə: Sayğacların yenilənməsi, cədvəl üçün metadatanın hesablanması.
Səhvlər və vacib məqamlar
Düzgün trigger növünü seçmək bəzən çətin ola bilər, bax bunları nəzərə al:
- Ən çox rast gəlinən səhvlərdən biri
FOR EACH STATEMENTtriggerindəOLDvəNEWməlumatlarından istifadə etməyə çalışmaqdır. Bu, səhv verəcək, çünki bu dəyişənlər yalnız sətir səviyyəsində triggerlərdə mövcuddur. - Sətir səviyyəsində triggerlər (
FOR EACH ROW) çoxlu sətirə təsir edən sorğularda əməliyyatları xeyli yavaşlada bilər. Həmişə performansı nəzərə al. - Triggerlərin potensial rekursiyasına diqqət et. Məsələn, trigger eyni cədvəldə məlumatı dəyişirsə, sonsuz dövrə səbəb ola bilər.
GO TO FULL VERSION