Ma'lumotlar bazasi dizayn patternlari, normalizatsiya va optimizatsiya texnikalarini o'rganish.
📋 Dars Rejasi
Normalizatsiya qoidalari
Denormalizatsiya strategiyalari
Indexing patterns
Partitioning strategies
Real-world examples
📊 Normalizatsiya Qoidalari
🔢 1NF - Birinchi Normal Forma
-- 1NF: Har bir ustun faqat bitta qiymatga ega
-- Yomon dizayn
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
phone_numbers VARCHAR(200) -- "123-456-7890, 987-654-3210"
);
-- Yaxshi dizayn
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE user_phones (
id INT PRIMARY KEY,
user_id INT REFERENCES users(id),
phone_number VARCHAR(20)
);
-- 3NF: Transitive dependency yo'q
-- Yomon dizayn
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(100),
dept_id INT,
dept_name VARCHAR(100),
dept_location VARCHAR(100)
);
-- Yaxshi dizayn
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(100),
dept_location VARCHAR(100)
);
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(100),
dept_id INT REFERENCES departments(dept_id)
);
🔢 BCNF - Boyce-Codd Normal Forma
-- BCNF: Har bir determinant superkey
-- Murakkab misol
CREATE TABLE course_instructors (
course_id INT,
instructor_id INT,
semester VARCHAR(20),
room VARCHAR(20),
PRIMARY KEY (course_id, semester)
);
-- BCNF'ga mos keladi chunki:
-- course_id, semester -> instructor_id, room
-- instructor_id, semester -> course_id, room
⚡ Denormalizatsiya Strategiyalari
🚀 Performance uchun Denormalizatsiya
-- Read-heavy application uchun
CREATE TABLE user_profiles (
user_id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100),
first_name VARCHAR(50),
last_name VARCHAR(50),
-- Denormalized fields
total_posts INT DEFAULT 0,
total_likes INT DEFAULT 0,
last_login TIMESTAMP,
-- Computed fields
full_name VARCHAR(101) GENERATED ALWAYS AS (first_name || ' ' || last_name)
);
-- Materialized view
CREATE MATERIALIZED VIEW user_stats AS
SELECT
u.user_id,
u.username,
COUNT(p.post_id) as total_posts,
COUNT(l.like_id) as total_likes,
MAX(p.created_at) as last_post
FROM users u
LEFT JOIN posts p ON u.user_id = p.user_id
LEFT JOIN likes l ON u.user_id = l.user_id
GROUP BY u.user_id, u.username;
💡 Denormalizatsiya Qoidalari
Read-heavy - Ko'p o'qish, kam yozish
Performance critical - Tezlik muhim
Consistency trade-off - Izchillik vs tezlik
Storage cost - Saqlash xarajati
📇 Indexing Patterns
🔍 Index Dizayn Strategiyalari
-- Composite index order
CREATE INDEX idx_user_posts ON posts (user_id, created_at DESC, status);
-- Covering index
CREATE INDEX idx_user_covering ON users (username, email, is_active)
INCLUDE (first_name, last_name);
-- Partial index
CREATE INDEX idx_active_users ON users (created_at)
WHERE is_active = true;
-- Functional index
CREATE INDEX idx_user_email_lower ON users (LOWER(email));
-- Bitmap index (PostgreSQL)
CREATE INDEX idx_user_status_bitmap ON users USING btree (status);
✅ Index Afzalliklari
Fast lookups - Tez qidirish
Sorting - Tartiblash
Joins - Bog'lanish
Covering - To'liq javob
⚠️ Index Kamchiliklari
Storage - Qo'shimcha joy
Write cost - Yozish sekinlashadi
Maintenance - Parvarish
Memory - Xotira ishlatadi
🗂️ Partitioning Strategies
📅 Range Partitioning
-- Range partitioning by date
CREATE TABLE orders (
order_id SERIAL,
customer_id INT,
order_date DATE,
amount DECIMAL(10,2)
) PARTITION BY RANGE (order_date);
-- Create partitions
CREATE TABLE orders_2024_q1 PARTITION OF orders
FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');
CREATE TABLE orders_2024_q2 PARTITION OF orders
FOR VALUES FROM ('2024-04-01') TO ('2024-07-01');
-- Hash partitioning
CREATE TABLE user_sessions (
session_id VARCHAR(100),
user_id INT,
created_at TIMESTAMP
) PARTITION BY HASH (user_id);
-- List partitioning
CREATE TABLE sales (
sale_id SERIAL,
region VARCHAR(50),
amount DECIMAL(10,2)
) PARTITION BY LIST (region);
🎯 Partitioning Strategiyalari
Range - Sana, raqam bo'yicha
Hash - Teng taqsimlash
List - Ro'yxat bo'yicha
Composite - Bir necha ustun
💼 Real-world Examples
🏪 E-commerce Database Design
-- Core entities
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE,
email VARCHAR(100) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
name VARCHAR(200),
description TEXT,
price DECIMAL(10,2),
category_id INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Denormalized for performance
CREATE TABLE product_stats (
product_id INT PRIMARY KEY,
view_count INT DEFAULT 0,
purchase_count INT DEFAULT 0,
avg_rating DECIMAL(3,2),
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Partitioned orders table
CREATE TABLE orders (
order_id SERIAL,
user_id INT,
order_date DATE,
total_amount DECIMAL(10,2),
status VARCHAR(20)
) PARTITION BY RANGE (order_date);