Hamımız insanıq və səhv etmək bizim təbiətimizdə var. Xüsusilə də, məlumat bazasında xarici açarlarla işləməyin incəliklərindən danışanda. Bu dərsdə sənə ən çox rast gəlinən səhvlərdən və "tələlərdən" necə qaçmaq lazım olduğunu göstərəcəm. Yaxşı bir məlumat bazası möhkəm körpü kimidir: haradasa səhv etsən, bütün konstruksiya çökə bilər. Gəlin baxaq, "məlumat körpülərini" necə qaydasında saxlamaq olar.
Səhv 1: Xarici açarda indeksin olmaması
Xarici açar əlavə edəndə, bazaya deyirsən: "Bu cədvəlləri bir-birinə bağla". Amma əgər bu xarici açar üçün ayrıca indeks yaratmasan, əlaqəli cədvəllərlə bağlı mürəkkəb sorğular zamanı performans ciddi şəkildə aşağı düşə bilər.
Problemin nümunəsi:
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
);
Görünüşdə hər şey əladır: cədvəllər yaradılıb, xarici açar var. Amma belə bir sorğu etsən:
SELECT *
FROM orders
JOIN customers ON orders.customer_id = customers.customer_id;
çoxlu məlumat olduqda belə sorğu çox yavaş işləyə bilər, çünki PostgreSQL join üçün uyğun indeks tapmayacaq.
Necə qaçmaq olar:
Həmişə xarici açarın istinad etdiyi sütun üçün indeks yarat. Bəzən PostgreSQL bunu avtomatik edir, amma ehtiyatlı olmaq yaxşıdır.
CREATE INDEX idx_customer_id ON orders(customer_id);
Səhv 2: Cədvəllərin yaradılma ardıcıllığının səhv olması
Təsəvvür et, cədvəlləri yaradırsan, amma istinad etdiyin cədvəl hələ yaradılmayıb, sən isə xarici açar əlavə etməyə çalışırsan. PostgreSQL etiraz edəcək və error atacaq, çünki istinad edilən cədvəli tapa bilmir.
Problemin nümunəsi:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
);
-- Oy, bəs customers cədvəli hanı?..
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
Nəticə: PostgreSQL error atacaq, çünki customers cədvəli hələ yoxdur.
Necə qaçmaq olar:
Əvvəlcə istinad etdiyin cədvəlləri yarat, sonra xarici açar əlavə et. Ardıcıllıq vacibdir. Düzgün yanaşma belədir:
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
);
Səhv 3: Cascade əməliyyatlarının sintaksisində səhvlər
Xarici açarlar tez-tez ON DELETE CASCADE və ya ON UPDATE RESTRICT kimi opsiyalarla gəlir. Amma təsadüfən bu qaydaları düzgün yazmasan, bazan gözlənilməz davranacaq. Məsələn, bir cədvəldə məlumat siləndə, bağlı cədvəllərdə heç nə dəyişməyəcək.
Problemin nümunəsi:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADEE
);
Diqqətli göz görəcək ki, burada typo var — CASCADEE səhv yazılıb. PostgreSQL bu səhvi buraxmayacaq.
Necə qaçmaq olar:
Düzgün yazmaq — işin yarısıdır. Əmin deyilsənsə, həmişə PostgreSQL-in rəsmi sənədlərinə bax.
Səhv 4: Məlumatların bütövlüyünün pozulması
Məlumatların bütövlüyü — istənilən bazanın "qutsal" hissəsidir və xarici açarlar bunu qorumağa kömək edir. Amma bəzən xarici açarı əlavə etməyi unudursan və hər şey alt-üst olur.
Problemin nümunəsi:
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT
);
-- Məlumat əlavə edirik
INSERT INTO orders (customer_id) VALUES (999);
Burada mövcud olmayan müştəri üçün sifariş əlavə etdik. Bu, məlumatların bütövlüyünü pozur və belə sifariş "asılı" qalacaq.
Necə qaçmaq olar:
Həmişə xarici açarlardan istifadə et ki, bir cədvəl mövcud olmayan yazıya istinad etməsin. Nümunəni düzgün yazaq:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
);
İndi "asılı" yazı əlavə etməyə cəhd etsən, error alacaqsan.
Səhv 5: Xarici açar errorlarını gizlətmək
Bəzən developer-lər uyğun olmayan məlumatı zorla əlavə etməyə çalışır, məsələn, INSERT ... ON CONFLICT istifadə edərək. Fikir yaxşıdır, amma xarici açarlarla bu, gözlənilməz nəticələrə gətirib çıxara bilər.
Problemin nümunəsi:
INSERT INTO orders (order_id, customer_id)
VALUES (1, 999)
ON CONFLICT DO NOTHING;
Nəticə: məlumat əlavə olunmadı, amma baza sənə niyə olmadığını demir. Nəzarəti itirirsən.
Necə qaçmaq olar:
Əgər ON CONFLICT istifadə edirsənsə, əvvəlcədən məlumatı yoxla. Məsələn:
INSERT INTO orders (order_id, customer_id)
SELECT 1, 999
WHERE EXISTS (
SELECT 1 FROM customers WHERE customer_id = 999
);
Səhv 6: ON DELETE olmadan asılı yazıların silinməsi
Əgər xarici açarın istinad etdiyi cədvəldən yazı silsən, amma ON DELETE CASCADE əlavə etməmisənsə, asılı yazılar bazada qalacaq və əlaqənin mənası pozulacaq.
Problemin nümunəsi:
DELETE FROM customers WHERE customer_id = 1;
-- orders cədvəlində customer_id = 1 olan yazılar hələ də qalır.
Necə qaçmaq olar:
ON DELETE CASCADE əlavə et ki, əlaqəli yazılar avtomatik silinsin:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE
);
İndi müştərini siləndə, uyğun sifarişlər də silinəcək.
Səhv 7: MANY-TO-MANY əlaqələrdə çətinliklər
MANY-TO-MANY əlaqələrlə işləyəndə bəzən birləşmiş primary key və ya indeks əlavə etməyi unudurlar.
Problemin nümunəsi:
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id),
course_id INT REFERENCES courses(course_id)
);
-- Oy! PRIMARY KEY yaddan çıxıb.
Necə qaçmaq olar:
Birləşmiş primary key və ya unique index əlavə et:
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id),
course_id INT REFERENCES courses(course_id),
PRIMARY KEY (student_id, course_id)
);
Səhv 8: Dairəvi istinadlar
Dairəvi istinadlar o vaxt yaranır ki, iki cədvəl bir-birinə xarici açarla istinad edir. Bu, qapalı dövrə yaradır və məlumat əlavə edəndə problem çıxarır.
Problemin nümunəsi:
CREATE TABLE table_a (
id SERIAL PRIMARY KEY,
table_b_id INT REFERENCES table_b(id)
);
CREATE TABLE table_b (
id SERIAL PRIMARY KEY,
table_a_id INT REFERENCES table_a(id)
);
Necə qaçmaq olar:
DEFERRABLE INITIALLY DEFERRED istifadə et ki, PostgreSQL məlumatların bütövlüyünü tranzaksiya bitəndən sonra yoxlaya bilsin:
CREATE TABLE table_a (
id SERIAL PRIMARY KEY,
table_b_id INT REFERENCES table_b(id) DEFERRABLE INITIALLY DEFERRED
);
Xarici açarlarla işləyərkən səhvlər təkcə development-i ləngitmir, həm də ciddi məlumat problemlərinə gətirib çıxara bilər. Bu siyahını "cheat sheet" kimi istifadə et ki, tipik "tələlərə" düşməyəsən. Unutma: xarici açar sənin dostundur, düşmənin yox. Əsas odur ki, düzgün işlədəsən və bazan uzunmüddətli layihənin etibarlı təməli olsun.
GO TO FULL VERSION