Tối Ưu Hóa Truy Vấn SQL Nâng Cao Trong Python: Từ CTEs Đến Window Functions

lúc 14:51 2 tháng 9, 2026
9 views

Khi phát triển các ứng dụng backend hiệu suất cao hoặc hệ thống xử lý dữ liệu lớn bằng Python, việc chỉ biết các câu lệnh truy vấn cơ bản là chưa đủ. Để khai thác tối đa sức mạnh từ cơ sở dữ liệu quan hệ như PostgreSQL hay MySQL, lập trình viên cần nắm vững các kỹ thuật nâng cao như Common Table Expressions (CTEs), Window Functions và chiến lược tối ưu hóa câu lệnh trực tiếp từ mã nguồn Python.

🏗️ Xử Lý Dữ Liệu Phức Tạp Với CTEs (Common Table Expressions) Trong Python

Common Table Expressions (CTEs) cho phép bạn tạo ra các bảng tạm thời ngay trong một câu lệnh SQL duy nhất, giúp mã nguồn dễ đọc và dễ bảo trì hơn so với việc sử dụng subquery lồng nhau quá sâu. Khi kết hợp với Python thông qua các thư viện như psycopg2 hoặc SQLAlchemy, bạn có thể dễ dàng truyền các tham số động vào câu lệnh.

Dưới đây là ví dụ minh họa cách sử dụng CTE phức tạp để tính toán doanh thu trung bình theo danh mục và lọc ra các sản phẩm vượt mức trung bình:

Code
import psycopg2
from psycopg2.extras import RealDictCursor

# Định nghĩa cấu hình kết nối cơ sở dữ liệu
DATABASE_CONFIG = {
    "dbname": "ecommerce_db",
    "user": "postgres",
    "password": "secure_password",
    "host": "localhost",
    "port": 5432
}

def fetch_high_performing_products(min_revenue_threshold):
    # Câu lệnh SQL sử dụng nhiều CTE phức tạp
    advanced_query = """
    WITH CategoryRevenue AS (
        -- CTE thứ nhất: Tính tổng doanh thu của từng sản phẩm
        SELECT 
            p.product_id,
            p.product_name,
            p.category_id,
            SUM(s.quantity * s.unit_price) AS total_revenue
        FROM products p
        JOIN sales s ON p.product_id = s.product_id
        GROUP BY p.product_id, p.product_name, p.category_id
    ),
    AverageCategorySales AS (
        -- CTE thứ hai: Tính doanh thu trung bình của từng danh mục
        SELECT 
            category_id,
            AVG(total_revenue) AS avg_category_revenue
        FROM CategoryRevenue
        GROUP BY category_id
    )
    -- Truy vấn chính kết hợp các CTE và tham số đầu vào từ Python
    SELECT 
        cr.product_name,
        cr.total_revenue,
        acs.avg_category_revenue
    FROM CategoryRevenue cr
    JOIN AverageCategorySales acs ON cr.category_id = acs.category_id
    WHERE cr.total_revenue > acs.avg_category_revenue
      AND cr.total_revenue >= %s
    ORDER BY cr.total_revenue DESC;
    """

    connection = None
    try:
        # Thiết lập kết nối đến cơ sở dữ liệu
        connection = psycopg2.connect(**DATABASE_CONFIG)
        with connection.cursor(cursor_factory=RealDictCursor) as cursor:
            # Thực thi truy vấn với tham số an toàn chống SQL Injection
            cursor.execute(advanced_query, (min_revenue_threshold,))
            query_results = cursor.fetchall()
            return query_results
    except Exception as database_error:
        print(f"Đã xảy ra lỗi khi thực thi truy vấn: {database_error}")
        return []
    finally:
        if connection:
            connection.close()

# Thực thi hàm với ngưỡng doanh thu tối thiểu
if __name__ == "__main__":
    threshold_value = 50000.00
    results = fetch_high_performing_products(threshold_value)
    for item in results:
        print(f"Sản phẩm: {item['product_name']} - Doanh thu: {item['total_revenue']}")

📊 Khai Thác Sức Mạnh Window Functions Để Phân Tích Dữ Liệu

Window Functions là công cụ cực kỳ mạnh mẽ cho phép thực hiện các phép tính toán học trên một tập hợp các hàng có liên quan đến hàng hiện tại mà không làm gộp nhóm dữ liệu như mệnh đề GROUP BY. Trong phân tích dữ liệu bằng Python, việc sử dụng các hàm như ROW_NUMBER(), RANK(), hoặc SUM() OVER giúp tối ưu hóa hiệu suất đáng kể so với việc kéo toàn bộ dữ liệu thô về xử lý trên RAM.

Đoạn mã dưới đây minh họa cách lấy ra top nhân viên có doanh số cao nhất trong từng phòng ban:

Code
import sqlite3

def get_top_employees_by_department(database_path):
    connection = sqlite3.connect(database_path)
    cursor = connection.cursor()

    # Câu lệnh SQL sử dụng Window Function RANK()
    ranking_query = """
    WITH RankedEmployees AS (
        SELECT 
            employee_name,
            department_name,
            sales_amount,
            RANK() OVER (
                PARTITION BY department_name 
                ORDER BY sales_amount DESC
            ) as sales_rank
        FROM employee_sales
    )
    SELECT 
        employee_name,
        department_name,
        sales_amount
    FROM RankedEmployees
    WHERE sales_rank <= 3;
    """

    cursor.execute(ranking_query)
    department_rankings = cursor.fetchall()
    
    connection.close()
    return department_rankings

⚡ Chiến Lược Tối Ưu Hóa Câu Lệnh SQL Khi Tích Hợp Vào Ứng Dụng Python

Khi ứng dụng Python xử lý hàng triệu bản ghi, ngay cả câu lệnh SQL được viết tốt cũng có thể gây nghẽn cổ chai nếu thiếu chiến lược tối ưu hóa toàn diện. Dưới đây là những nguyên tắc cốt lõi giúp tăng tốc độ hệ thống:

  • Sử dụng chỉ mục chiến lược (Indexing): Đảm bảo các cột tham gia vào mệnh đề WHERE, JOIN, hoặc ORDER BY đã được tạo Index hợp lệ.
  • Tránh truy vấn lặp N+1 (N+1 Query Problem): Khi sử dụng ORM như SQLAlchemy, hãy tận dụng tính năng eager loading thay vì thực hiện vòng lặp truy vấn liên tục trong Python.
  • Phân trang dữ liệu lớn (Pagination): Thay vì lấy toàn bộ kết quả, hãy sử dụng cơ chế phân trang dựa trên khóa chính hoặc LIMIT/OFFSET hợp lý.
  • Phân tích thực thi câu lệnh (EXPLAIN ANALYZE): Luôn kiểm tra kế hoạch thực thi của hệ quản trị cơ sở dữ liệu trước khi đưa mã nguồn lên môi trường production.

Việc kết hợp thành thạo các kỹ thuật SQL nâng cao cùng với mã nguồn Python chuẩn mực không chỉ giúp cải thiện tốc độ xử lý mà còn tiết kiệm tối đa tài nguyên hạ tầng.

📝 Bài tập thực hành nâng cao năng lực

Bài tập 1: Tính tổng tích lũy doanh thu theo thời gian (Running Total)

Yêu cầu thực hành: Viết một hàm Python sử dụng Window Function (SUM() OVER) để tính doanh thu tích lũy theo từng ngày cho mỗi cửa hàng, giúp ban quản lý theo dõi sát sao biểu đồ tăng trưởng dòng tiền.

Code
import psycopg2
from psycopg2.extras import RealDictCursor

DATABASE_CONFIG = {
    "dbname": "retail_db",
    "user": "postgres",
    "password": "secure_password",
    "host": "localhost",
    "port": 5432
}

def get_running_revenue_by_store(target_store_id):
    # Câu lệnh SQL sử dụng Window Function với khung cửa sổ (Frame Clause)
    running_total_query = """
    SELECT 
        sale_date,
        daily_revenue,
        SUM(daily_revenue) OVER (
            PARTITION BY store_id 
            ORDER BY sale_date 
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) AS cumulative_revenue
    FROM daily_store_sales
    WHERE store_id = %s
    ORDER BY sale_date ASC;
    """

    connection = None
    try:
        connection = psycopg2.connect(**DATABASE_CONFIG)
        with connection.cursor(cursor_factory=RealDictCursor) as cursor:
            # Truyền tham số store_id an toàn vào câu lệnh
            cursor.execute(running_total_query, (target_store_id,))
            execution_results = cursor.fetchall()
            return execution_results
    except Exception as query_error:
        print(f"Lỗi khi thực thi truy vấn tổng tích lũy: {query_error}")
        return []
    finally:
        if connection:
            connection.close()

# Thực thi hàm thử nghiệm cho cửa hàng có ID bằng 101
if __name__ == "__main__":
    store_id_param = 101
    results = get_running_revenue_by_store(store_id_param)
    for record in results:
        print(f"Ngày: {record['sale_date']} | Doanh thu ngày: {record['daily_revenue']} | Tích lũy: {record['cumulative_revenue']}")

Bài tập 2: Truy vấn phân cấp danh mục đa cấp sử dụng Recursive CTE

Yêu cầu thực hành: Viết hàm Python kết hợp Recursive CTE để quét toàn bộ cây phân cấp danh mục sản phẩm (cha - con - cháu) bắt đầu từ một danh mục gốc bất kỳ, phục vụ cho hệ thống lọc sản phẩm đa tầng trên website thương mại điện tử.

Code
import psycopg2

def fetch_subcategories_hierarchy(root_category_id):
    # Câu lệnh SQL sử dụng Recursive CTE để duyệt cây phân cấp
    recursive_query = """
    WITH RECURSIVE CategoryTree AS (
        -- Bước neo (Anchor Member): Lấy danh mục gốc ban đầu
        SELECT 
            category_id, 
            category_name, 
            parent_id, 
            1 AS hierarchy_level
        FROM categories
        WHERE category_id = %s
        
        UNION ALL
        
        -- Bước đệ quy (Recursive Member): Lấy các danh mục con liên kết cấp tiếp theo
        SELECT 
            c.category_id, 
            c.category_name, 
            c.parent_id, 
            ct.hierarchy_level + 1
        FROM categories c
        JOIN CategoryTree ct ON c.parent_id = ct.category_id
    )
    -- Truy vấn tổng hợp từ kết quả của Recursive CTE
    SELECT 
        category_id, 
        category_name, 
        parent_id, 
        hierarchy_level
    FROM CategoryTree
    ORDER BY hierarchy_level ASC, category_name ASC;
    """

    database_connection = psycopg2.connect(
        dbname="ecommerce_db",
        user="postgres",
        password="secure_password",
        host="localhost",
        port=5432
    )
    
    try:
        with database_connection.cursor() as cursor:
            cursor.execute(recursive_query, (root_category_id,))
            category_hierarchy_data = cursor.fetchall()
            return category_hierarchy_data
    except Exception as error_detail:
        print(f"Đã xảy ra lỗi hệ thống khi quét phân cấp danh mục: {error_detail}")
        return []
    finally:
        database_connection.close()

Bình luận

Đăng nhập để để lại bình luận.
Chưa có bình luận nào cho bài viết này.

Bài viết liên quan