-- 1. Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΡΠΌΠ°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΡΠ΅ ΡΠ°Π±Π»ΠΈΡΡ Ρ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠΌΠΈ ΠΈΠ½Π΄Π΅ΠΊΡΠ°ΠΌΠΈ ΠΈ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΡΠΌΠΈ
DROP TABLE IF EXISTS order_items CASCADE;
DROP TABLE IF EXISTS orders CASCADE;
DROP TABLE IF EXISTS customers CASCADE;
-- Π’Π°Π±Π»ΠΈΡΠ° customers Ρ ΠΎΠΏΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΌΠΈ ΠΈΠ½Π΄Π΅ΠΊΡΠ°ΠΌΠΈ
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE, -- ΠΠ°ΠΌΠ΅Π½ΡΠ΅ΠΌ Π΄Π²Π° ΠΈΠ½Π΄Π΅ΠΊΡΠ° Π½Π° UNIQUE CONSTRAINT
created_at TIMESTAMP DEFAULT now() NOT NULL
);
-- Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΠ΄ΠΈΠ½ ΠΈΠ½Π΄Π΅ΠΊΡ Π΄Π»Ρ email
CREATE INDEX idx_customers_email ON customers(email);
-- Π’Π°Π±Π»ΠΈΡΠ° orders Ρ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΡΠΌΠΈ ΠΈΠ½Π΄Π΅ΠΊΡΠ°ΠΌΠΈ ΠΈ Π²Π½Π΅ΡΠ½ΠΈΠΌΠΈ ΠΊΠ»ΡΡΠ°ΠΌΠΈ
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INT NOT NULL REFERENCES customers(id),
amount DECIMAL(10,2) CHECK (amount >= 0),
order_date DATE NOT NULL,
status VARCHAR(20) NOT NULL,
notes TEXT,
CONSTRAINT valid_status CHECK (status IN ('pending', 'completed', 'canceled'))
);
-- ΠΠ½Π΄Π΅ΠΊΡΡ Π΄Π»Ρ ΡΠ°ΡΡΡΡ Π·Π°ΠΏΡΠΎΡΠΎΠ²
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_orders_order_date ON orders(order_date);
CREATE INDEX idx_orders_status ON orders(status);
-- Π’Π°Π±Π»ΠΈΡΠ° order_items Ρ ΠΎΠΏΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΌΠΈ ΠΈΠ½Π΄Π΅ΠΊΡΠ°ΠΌΠΈ
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id INT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id INT NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0),
price DECIMAL(10,2) NOT NULL CHECK (price >= 0)
);
-- ΠΠ½Π΄Π΅ΠΊΡΡ Π΄Π»Ρ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠΉ ΠΈ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠΈ
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
CREATE INDEX idx_order_items_quantity ON order_items(quantity);
-- 2. ΠΠ°ΠΏΠΎΠ»Π½ΡΠ΅ΠΌ ΡΠ°Π±Π»ΠΈΡΡ ΡΠ΅ΡΡΠΎΠ²ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ
INSERT INTO customers (name, email)
SELECT
'Customer ' || i,
'customer' || i || CASE WHEN i%2=0 THEN '@gmail.com' ELSE '@example.com' END
FROM generate_series(1, 10000) AS i;
-- 100,000 Π·Π°ΠΊΠ°Π·ΠΎΠ² (ΠΏΠΎ 10 Π½Π° ΠΊΠ»ΠΈΠ΅Π½ΡΠ°)
INSERT INTO orders (customer_id, amount, order_date, status)
SELECT
(random() * 9999)::int + 1,
(random() * 1000)::numeric(10,2),
(now() - (random() * 365)::int * '1 day'::interval)::date,
CASE WHEN random() > 0.5 THEN 'completed' ELSE 'pending' END
FROM generate_series(1, 100000);
-- 300,000 ΠΏΠΎΠ·ΠΈΡΠΈΠΉ Π·Π°ΠΊΠ°Π·ΠΎΠ² (ΠΏΠΎ 3 Π½Π° Π·Π°ΠΊΠ°Π·)
INSERT INTO order_items (order_id, product_id, quantity, price)
SELECT
(random() * 99999)::int + 1,
(random() * 100)::int + 1,
(random() * 10)::int + 1,
(random() * 500)::numeric(10,2)
FROM generate_series(1, 300000);
-- 3. ΠΠ½Π°Π»ΠΈΠ·ΠΈΡΡΠ΅ΠΌ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΡ ΡΠ°Π±Π»ΠΈΡ
ANALYZE customers;
ANALYZE orders;
ANALYZE order_items;
-- 4. ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠ½ΡΠ΅ Π·Π°ΠΏΡΠΎΡΡ Ρ EXPLAIN ANALYZE
-- ΠΠ°ΠΏΡΠΎΡ 1: Π―Π²Π½ΡΠΉ Π²ΡΠ±ΠΎΡ ΠΏΠΎΠ»Π΅ΠΉ + ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ JOIN
EXPLAIN ANALYZE
SELECT
o.id AS order_id,
o.order_date,
c.name AS customer_name,
c.email,
oi.product_id,
oi.quantity
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items oi ON o.id = oi.order_id
WHERE c.email LIKE '%@gmail.com'
AND o.order_date BETWEEN '2023-01-01' AND CURRENT_DATE
ORDER BY o.order_date DESC;
-- ΠΠ°ΠΏΡΠΎΡ 2: ΠΠ°ΠΌΠ΅Π½Π° ΠΏΠΎΠ΄Π·Π°ΠΏΡΠΎΡΠ° Π½Π° JOIN
EXPLAIN ANALYZE
SELECT
c.name,
COUNT(o.id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE c.created_at > '2023-01-01'
GROUP BY c.id;
-- ΠΠ°ΠΏΡΠΎΡ 3: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΡΠΉ ΠΈΠ½Π΄Π΅ΠΊΡ
EXPLAIN ANALYZE
SELECT id, name, email
FROM customers
WHERE LOWER(name) = 'customer 5000';
-- ΠΠ°ΠΏΡΠΎΡ 4: ΠΠ°Π³ΠΈΠ½Π°ΡΠΈΡ ΠΈ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ ΠΏΠΎ ΠΏΡΠ΅ΡΠΈΠΊΡΡ
EXPLAIN ANALYZE
SELECT
c.id AS customer_id,
c.name,
o.id AS order_id,
oi.product_id
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE c.name LIKE 'Customer 1%'
LIMIT 100;
-- ΠΠ°ΠΏΡΠΎΡ 5: ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΡΠ»ΠΎΠ²ΠΈΡ Π΄Π°ΡΡ
EXPLAIN ANALYZE
UPDATE orders
SET notes = 'processed'
WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';
-- ΠΠ°ΠΏΡΠΎΡ 6: ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΠ° Π΄Π»Ρ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π°
EXPLAIN ANALYZE
DELETE FROM order_items
WHERE quantity < 2;