Skip to content
Back to Blog
1 min read

Leveraging MySQL 8.0 Features on Azure

I wrote “Leveraging MySQL 8.0 Features on Azure” to share practical, production-minded guidance on this topic.

Window Functions

MySQL 8.0 introduced window functions for advanced analytics:

-- Ranking orders by amount within each customer
SELECT
    customer_id,
    order_id,
    order_date,
    amount,
    ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY amount DESC) as rank_by_amount,
    SUM(amount) OVER (PARTITION BY customer_id) as customer_total,
    amount / SUM(amount) OVER (PARTITION BY customer_id) * 100 as percent_of_total
FROM orders;

-- Running totals and moving averages
SELECT
    order_date,
    amount,
    SUM(amount) OVER (ORDER BY order_date) as running_total,
    AVG(amount) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as moving_avg_7day
FROM daily_sales;

Common Table Expressions (CTEs)

-- Recursive CTE for hierarchical data
WITH RECURSIVE category_tree AS (
    -- Base case: root categories
    SELECT id, name, parent_id, 0 as level, CAST(name AS CHAR(1000)) as path
    FROM categories
    WHERE parent_id IS NULL

    UNION ALL

    -- Recursive case: child categories
    SELECT c.id, c.name, c.parent_id, ct.level + 1,
           CONCAT(ct.path, ' > ', c.name)
    FROM categories c
    JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree ORDER BY path;

-- Non-recursive CTE for readability
WITH monthly_sales AS (
    SELECT
        DATE_FORMAT(order_date, '%Y-%m') as month,
        SUM(amount) as total_sales
    FROM orders
    GROUP BY DATE_FORMAT(order_date, '%Y-%m')
),
monthly_growth AS (
    SELECT
        month,
        total_sales,
        LAG(total_sales) OVER (ORDER BY month) as prev_month_sales
    FROM monthly_sales
)
SELECT
    month,
    total_sales,
    prev_month_sales,
    ROUND((total_sales - prev_month_sales) / prev_month_sales * 100, 2) as growth_percent
FROM monthly_growth;

JSON Enhancements

-- Create table with JSON column
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255),
    attributes JSON,
    INDEX idx_brand ((CAST(attributes->>'$.brand' AS CHAR(50))))
);

-- Insert JSON data
INSERT INTO products (name, attributes) VALUES
('Laptop', '{"brand": "Dell", "specs": {"ram": "16GB", "storage": "512GB SSD"}, "tags": ["electronics", "computers"]}'),
('Phone', '{"brand": "Apple", "specs": {"storage": "256GB"}, "tags": ["electronics", "mobile"]}');

-- Query JSON data
SELECT
    name,
    attributes->>'$.brand' as brand,
    attributes->>'$.specs.ram' as ram,
    JSON_CONTAINS(attributes->'$.tags', '"electronics"') as is_electronics
FROM products
WHERE attributes->>'$.brand' = 'Dell';

-- JSON table functions
SELECT
    p.name,
    tag.value as tag
FROM products p,
JSON_TABLE(p.attributes, '$.tags[*]' COLUMNS (value VARCHAR(50) PATH '$')) as tag;

Invisible Indexes

-- Create an invisible index
CREATE INDEX idx_email ON users(email) INVISIBLE;

-- Test query performance without the index
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

-- Make the index visible if it helps
ALTER TABLE users ALTER INDEX idx_email VISIBLE;

Descending Indexes

-- Create a composite index with descending order
CREATE INDEX idx_orders_date_amount ON orders(order_date DESC, amount DESC);

-- This query benefits from the descending index
SELECT * FROM orders
ORDER BY order_date DESC, amount DESC
LIMIT 100;

Atomic DDL

-- DDL operations are now atomic
CREATE TABLE new_table (
    id INT PRIMARY KEY,
    data VARCHAR(255)
);

-- If this fails, no partial changes remain
ALTER TABLE new_table
    ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    ADD COLUMN updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    ADD INDEX idx_created (created_at);

Resource Groups (Performance Tuning)

-- Create a resource group for batch processing
CREATE RESOURCE GROUP batch_processing
    TYPE = USER
    VCPU = 2-3
    THREAD_PRIORITY = 10;

-- Assign a connection to the resource group
SET RESOURCE GROUP batch_processing;

MySQL 8.0 features significantly enhance your application capabilities on Azure Database for MySQL Flexible Server.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.