diff --git a/dmedvedev/10.3.Optimization of select.sql b/dmedvedev/10.3.Optimization of select.sql index 33ec8c9..3c06a7d 100644 --- a/dmedvedev/10.3.Optimization of select.sql +++ b/dmedvedev/10.3.Optimization of select.sql @@ -51,7 +51,7 @@ SELECT id, name, age FROM users WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01' - AND country = 'россия' + AND country IN ('россия', 'Россия', 'РОССИЯ') AND age > 25; Исправлено: выдача колонок "все" заменено на "определенные", логика в where с числами переработана, соответствие определенному году переработано и убрал функцию LOWER. diff --git a/dmedvedev/10.4.Explain.sql b/dmedvedev/10.4.Explain.sql index 3ef5e4d..e1b450a 100644 --- a/dmedvedev/10.4.Explain.sql +++ b/dmedvedev/10.4.Explain.sql @@ -69,8 +69,7 @@ WHERE id = 1; --Думаю, потому что также используется функция LOWER внутри WHERE 4. Как исправить запрос, чтобы индекс заработал? -CREATE INDEX idx_email ON users(email); ---я добавил индекс, но все равно EXPLAIN ANALYZE показывается Seq Scan. В чем проблема? +CREATE INDEX idx_email ON users(LOWER(email)) ---------- --Задача 7 — Функции убивают индексы diff --git a/dmedvedev/10.5.Porydok.sql b/dmedvedev/10.5.Porydok.sql index 326ab1e..5b1c3de 100644 --- a/dmedvedev/10.5.Porydok.sql +++ b/dmedvedev/10.5.Porydok.sql @@ -262,7 +262,7 @@ **❓ Вопросы:** 1. Когда выполняется подзапрос в `SELECT`? - В самом начале. + Подзапрос в SELECT вычисляется после того, как отработали секции FROM и WHERE 2. Можно ли использовать алиас `orders_count` в `WHERE`? Нет, потому что WHERE не видит алиасы @@ -270,14 +270,15 @@ 3. Можно ли использовать его в `ORDER BY`? Да, потому что order by выполняется после SELECT - 4. Перепиши этот запрос через `JOIN`. Какой вариант быстрее? Проверь с `EXPLAIN ANALYZE`! 0.065-0.15 + 4. Перепиши этот запрос через `JOIN`. Какой вариант быстрее? Проверь с `EXPLAIN ANALYZE`! SELECT u.name, u.age, COUNT(o.id) AS orders_count FROM users u LEFT JOIN orders o ON o.user_id = u.id + WHERE u.country = 'Россия' GROUP BY u.name, u.age ORDER BY orders_count DESC; - Второй запрос через JOIN выполняется дольше (0.06 и 0.08 мс соответственно) \ No newline at end of file + Второй запрос через JOIN выполняется быстрее (0.13 и 0.1 мс соответственно) \ No newline at end of file diff --git a/dmedvedev/11.4 Pet project Cohort_analysis.sql b/dmedvedev/11.4 Pet project Cohort_analysis.sql index 42a5d55..ac0f2c1 100644 --- a/dmedvedev/11.4 Pet project Cohort_analysis.sql +++ b/dmedvedev/11.4 Pet project Cohort_analysis.sql @@ -2,36 +2,32 @@ CREATE MATERIALIZED VIEW user_cohort_analysis AS SELECT - TO_CHAR(pu.cohort_month, 'YYYY-MM') AS MONTH, + TO_CHAR(pu.cohort_month, 'YYYY-MM') AS month, COUNT(DISTINCT pu.id) AS users_in_cohort, COUNT(DISTINCT pe.user_id) AS enrolled_users, COUNT(DISTINCT plv.user_id) AS active_users, - --ROUND(COUNT(DISTINCT plv.user_id) * 100.0 / COUNT(DISTINCT pu.id), 2) || '%' AS retention_rate, - ROUND(COUNT(DISTINCT pe.user_id) * 100.0 / COUNT(DISTINCT pu.id), 2) || '%' AS retention_rate, - ROUND(AVG((SELECT COUNT(pe.id) - FROM pet_enrollments pe)) / COUNT(DISTINCT pu.id), 2) AS avg_courses_per_user, - (SELECT + ROUND(COUNT(DISTINCT plv.user_id) * 100.0 / COUNT(DISTINCT pu.id), 2) || '%' AS retention_rate, + ROUND(COUNT(DISTINCT pe.id) * 1.0 / COUNT(DISTINCT pu.id), 2) AS avg_courses_per_user, + ( + SELECT ROUND(AVG(table_first_viewed_at.first_viewed_at::date - pu2.registration_date::date), 2) FROM pet_users pu2 - LEFT JOIN ( + JOIN ( SELECT plv2.user_id, MIN(plv2.viewed_at) AS first_viewed_at FROM pet_lesson_views plv2 GROUP BY plv2.user_id - ) AS table_first_viewed_at - - ON pu2.id = table_first_viewed_at.user_id - + ) AS table_first_viewed_at ON pu2.id = table_first_viewed_at.user_id WHERE DATE_TRUNC('month', pu2.registration_date) = pu.cohort_month - ) AS avg_time_to_first_view + ) AS avg_time_to_first_view FROM ( - SELECT + SELECT *, DATE_TRUNC('month', registration_date) AS cohort_month FROM pet_users - ) AS pu +) AS pu LEFT JOIN pet_enrollments pe ON pu.id = pe.user_id LEFT JOIN pet_lesson_views plv ON pu.id = plv.user_id @@ -39,3 +35,4 @@ GROUP BY pu.cohort_month ORDER BY pu.cohort_month; + diff --git a/dmedvedev/11.7 Pet Project Additional tasks.sql b/dmedvedev/11.7 Pet Project Additional tasks.sql index bb0a73a..ba5f05a 100644 --- a/dmedvedev/11.7 Pet Project Additional tasks.sql +++ b/dmedvedev/11.7 Pet Project Additional tasks.sql @@ -1,24 +1,24 @@ -- 1. Задание 1: Анализ drop-off точек -- Используя conversion_funnel, найди курсы с самым большим процентом отвала между этапами enrolled → started (WHERE stage_name IN (...)) -WITH - drop_off - AS - ( - SELECT - course_id, - stage_name, - users_count, - LAG(users_count) OVER (PARTITION BY course_id) AS prev - - FROM conversion_funnel - ) - +WITH drop_off AS ( + SELECT + course_id, + stage_name, + users_count, + LAG(users_count) OVER ( + PARTITION BY course_id + ORDER BY stage_name + ) AS prev + FROM conversion_funnel + WHERE stage_name IN ('enrolled', 'started') +) SELECT - course_id, - ROUND(1 - users_count * 1.0 / NULLIF(prev, 0), 2) * 100 || '%' AS percent_of_drop + course_id, + ROUND((1 - users_count * 1.0 / NULLIF(prev, 0)) * 100, 2) || '%' AS percent_of_drop FROM drop_off WHERE stage_name = 'started' -ORDER BY percent_of_drop DESC +ORDER BY (1 - users_count * 1.0 / NULLIF(prev, 0)) DESC; + -- ОТВЕТ: Самые большие проценты отвала между enrolled и started замечены на курсе 1 и 3 (62 и 67% соответственно). diff --git a/dmedvedev/2.1.theory_bd_indexes.sql b/dmedvedev/2.1.theory_bd_indexes.sql index 809bc5e..828f386 100644 --- a/dmedvedev/2.1.theory_bd_indexes.sql +++ b/dmedvedev/2.1.theory_bd_indexes.sql @@ -199,4 +199,5 @@ **Ответ — текстом:** В чём выгода индекса и где он не поможет - Индекс помогает искать данные быстрее (индекс это как содержание в книге). Индекс не поможет в тех столбцах, где все данные в столбце различаются, например email. + Индекс помогает искать данные быстрее (индекс это как содержание в книге) за счет плана в виде дерева. + Индекс не поможет в тех столбцах, где уникальность данных мала, а также где есть сортировка по знакам >, < или поиск по части строки = "%abc". diff --git a/dmedvedev/2.2.theory_bd_partitions.sql b/dmedvedev/2.2.theory_bd_partitions.sql index 0de96c9..c434d57 100644 --- a/dmedvedev/2.2.theory_bd_partitions.sql +++ b/dmedvedev/2.2.theory_bd_partitions.sql @@ -30,7 +30,7 @@ - по дням. 2. Для каждого варианта напиши: - примерно сколько будет партиций за 10 лет; - по годам - 10 * 1 = 10, по месяцам - 10 * 12 = 120, по дням 366 * 2 + 365 * 4 = 2652. + по годам - 10 * 1 = 10, по месяцам - 10 * 12 = 120, по дням 366 * 2 + 365 * 8 = 3652. - плюсы и минусы (удаление старых данных, поддержка, скорость запросов). diff --git a/dmedvedev/ddl.sql b/dmedvedev/ddl.sql index 9893ff3..fcb53ed 100644 --- a/dmedvedev/ddl.sql +++ b/dmedvedev/ddl.sql @@ -1,4 +1,5 @@ -CREATE TABLE users ( +CREATE TABLE users +( id INT PRIMARY KEY NOT NULL, name VARCHAR(100) NOT NULL, age INT, @@ -8,7 +9,8 @@ CREATE TABLE users ( created_at TIMESTAMPTZ NOT NULL ); -CREATE TABLE products ( +CREATE TABLE products +( id INT PRIMARY KEY NOT NULL, name VARCHAR(100) NOT NULL, category VARCHAR(50), @@ -16,15 +18,17 @@ CREATE TABLE products ( in_stock BOOLEAN ); -CREATE TABLE orders ( - id INT PRIMARY KEY NOT NULL, +CREATE TABLE orders +( + id SERIAL PRIMARY KEY NOT NULL, user_id INT, order_date TIMESTAMPTZ NOT NULL, status VARCHAR(20), FOREIGN KEY (user_id) REFERENCES users(id) ); -CREATE TABLE order_items ( +CREATE TABLE order_items +( order_id INT NOT NULL, product_id INT NOT NULL, quantity INT NOT NULL,