Məlumatları ideal şəkildə normallaşdıranda, hər cədvəl maksimum dərəcədə yığcam olur və oradakı info yalnız bir prinsipə cavab verir. Amma real sorğular üçün (məsələn, "SQL kursuna hansı tələbələr yazılıb?") bəzən bir dəstə cədvəli birləşdirmək lazım gəlir. Cədvəl sayı artdıqca sorğular da çətinləşir, sistem daha çox "lopata" işləyir.
Yəqin ki, əvvəlki dərslərdən JOIN-larla artıq tanışsan. Bax, normal dizayn olunmuş verilənlər bazasında lazım ola biləcək sorğu nümunəsi:
SELECT students.name, courses.title
FROM students
JOIN enrollments ON students.id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.id
WHERE courses.title = 'SQL';
Səslənməsi asandır, amma arxa planda server cəhənnəm işi görür: hər cədvəli oxuyur, məlumatları birləşdirir, filtrləyir... Bəs cədvəllər çox-çox böyük olsa? Məntiqlə, performans aşağı düşəcək.
Döyüşlər: normallaşdırma vs sürət
Xoşbəxtlikdən (ya da bəlkə də yox?), real həyatda verilənlər bazası — kompromisdir. Tam normallaşdırma məlumatların bütövlüyünü qoruyur, amma mürəkkəb sorğuları yavaşdırır. Əgər verilənlər bazası əsasən analitika və hesabatlar üçün istifadə olunacaqsa, bəzən onu denormallaşdırmaq sərfəlidir. Bu, 10 balaca qutunu bir böyük sandıqla əvəzləmək kimidir: məlumatı çıxarmaq tez olur, amma yenidən düzülüş çətinləşir.
Normallaşdırmanı "buraxmaq" nə vaxt olar?
Elə ssenarilər var ki, denormallaşdırma daha yaxşıdır:
Tez-tez istifadə olunan aqreqatlar
Məsələn, təsəvvür elə ki, sistem hər gün hər kursda neçə tələbə olduğunu hesablamaq üçün sorğu atır. Normallaşdırılmış struktura görə, daimJOIN və
COUNT() işlətmək lazım gəlir. Bunun əvəzinə "Courses" cədvəlinə
student_count adlı sütun əlavə edib, ora tələbə əlavə/çıxaranda avtomatik yeniləyə bilərsən.
-- Denormallaşdırılmış sütun
UPDATE courses
SET student_count = (
SELECT COUNT(*)
FROM enrollments
WHERE enrollments.course_id = courses.id
);
Tez-tez edilən hesabatlar
Əgər müştəri hər gün "Kim, harada, nə vaxt alıb?" tipli hesabat istəyirsə, ən rahatı hazır sətirlərlə denormallaşdırılmış cədvəl saxlamaqdır: "Müştərinin adı, məhsul, tarix". Əsas cədvəl böyüyəcək, amma məlumatı almaq sürətlənəcək.
Çox oxuma, az yazma
Əgər verilənlər bazası əsasən oxumaq üçün istifadə olunursa (məsələn, analitika), performans üçün normallaşdırmadan keçmək olar.
Çətin əlaqələrdə birləşmələri azaltmaq
Əgər cədvəllər arasında çoxqatlı (nested) əlaqələr varsa vəJOIN kabusa çevrilibsə, bəzi normallaşdırma səviyyələrini çıxart.
Nümunə: denormallaşdırma necə sürətləndirir?
İnternet mağazasının normallaşdırılmış cədvəlləri var:
products cədvəli |
orders cədvəli |
order_items cədvəli |
|---|---|---|
| id | id | id |
| name | date | order_id |
| price | customer_id | product_id |
| quantity |
Hər sifariş (orders) sifariş sətirlərindən (order_items) ibarətdir. Gəlin baxaq, mağaza nə qədər pul qazanıb:
SELECT SUM(order_items.quantity * products.price) AS total_revenue
FROM order_items
JOIN products ON order_items.product_id = products.id;
order_items və products birləşməsi böyük həcmdə məlumatda sorğunu yavaşdıracaq.
Denormallaşdırılmış struktur
İndi təsəvvür elə ki, order_items cədvəlində "artıq" total_price sütunu var (denormallaşdırma):
order_items cədvəli |
|---|
| id |
| order_id |
| product_id |
| quantity |
| total_price |
İndi sorğu lap sadə olur:
SELECT SUM(total_price) AS total_revenue
FROM order_items;
Beləliklə, JOIN-dan qaçırıq və icra sürətlənir.
Praktiki tapşırıq: "Satışlar" bazasını optimallaşdır
Verilir: normallaşdırılmış cədvəllər
products cədvəli |
sales cədvəli |
|---|---|
| id | id |
| name | product_id |
| price | date |
| quantity |
Tapşırıq: "Hər məhsuldan nə qədər qazanc əldə olunub?" tipli tez-tez sorğuları sürətləndirmək.
Addım 1: sales cədvəlinə total_price sütunu əlavə edirik:
ALTER TABLE sales ADD COLUMN total_price NUMERIC;
Addım 2: Bu sütunu mövcud məlumatlar üçün doldururuq:
UPDATE sales
SET total_price = quantity * (
SELECT price
FROM products
WHERE products.id = sales.product_id
);
Addım 3: Sorğuları daha sürətli et:
SELECT product_id, SUM(total_price) AS total_revenue
FROM sales
GROUP BY product_id;
Amma! Denormallaşdırmanın bədəli var
Başa düşürsən ki, "daha sürətli" həmişə "daha yaxşı" demək deyil. Denormallaşdırmada belə problemlər çıxır:
Artıq yaddaş sərfi
total_price sütunu — məlumatın kopyasıdır, əlavə yer tutur.
Yeniləmələrin çətinliyi
Əgər məhsulun qiyməti products cədvəlində dəyişsə, uyğun total_price sütununu əl ilə yeniləməlisən. Bu, uyğunsuzluqlara səbəb ola bilər.
Insert, update və delete anomaliyaları
Məlumat asanlıqla "uyğunsuzlaşır", əgər denormallaşdırılmış məlumatı yeniləməyi unutsan. Məsələn, məhsulun qiyməti dəyişəndə, bu avtomatik olmur.
Balans: qızıl ortanı necə tapmalı?
Sənin üçün nə vacibdir: performans, yoxsa struktur? Əgər baza əsasən oxunursa, sorğulara uyğunlaş.
Denormallaşdırmanı nöqtəvi əlavə et. Məsələn, yalnız əsas rəqəmlər və hesabatlar üçün.
Denormallaşdırılmış məlumatların yenilənməsini avtomatlaşdır. Uyğunsuzluq olmasın deyə trigger-lər və ya task-lar istifadə et.
GO TO FULL VERSION