Mastering SQL: Optimizing Queries with Smarter Techniques

SQL is powerful, but writing efficient and readable queries makes all the difference. While working on various databases, I’ve discovered some underrated SQL concepts that improve both performance and maintainability.

Let’s explore some key SQL best practices, with practical examples to help you optimize your queries!

1️⃣ COALESCE vs. ISNULL – Handling NULLs the Right Way

Both COALESCE and ISNULL handle NULL values, but COALESCE offers more flexibility.

SELECT ISNULL(NULL, 'Fallback');   -- Returns: 'Fallback'
SELECT COALESCE(NULL, NULL, 'Fallback', 'Another Value');  -- Returns: 'Fallback'

Use COALESCE when checking multiple values, as it returns the first non-null value.
ISNULL is limited to two arguments and may cause unexpected type conversions.


2️⃣ Avoid IN – Use JOIN for Better Performance

Using IN in subqueries is often slower than a JOIN.

-- Using IN (Slower)
SELECT name FROM Employees WHERE department_id IN (SELECT id FROM Departments WHERE location = 'NY');

-- Using JOIN (Faster)
SELECT e.name FROM Employees e JOIN Departments d ON e.department_id = d.id WHERE d.location = 'NY';

JOIN is optimized by the SQL engine and executes faster on large datasets.


3️⃣ Aliases – A Good Practice Even for Simple Queries

Aliases (AS) improve readability and make queries more maintainable.

SELECT e.name AS EmployeeName, d.name AS DepartmentName 
FROM Employees e 
JOIN Departments d ON e.department_id = d.id;

✔ Even in small queries, aliasing enhances clarity and is extremely helpful in complex queries.


4️⃣ GROUP BY vs. PARTITION BY – Understanding the Difference

GROUP BY aggregates data into a single row per group, whereas PARTITION BY preserves all rows and applies window functions.

-- GROUP BY (Collapses rows)
SELECT department_id, COUNT(*) AS EmployeeCount FROM Employees GROUP BY department_id;

-- PARTITION BY (Keeps all rows)
SELECT name, department_id, COUNT(*) OVER (PARTITION BY department_id) AS EmployeeCount FROM Employees;

Use GROUP BY for summary data.
Use PARTITION BY when you need group-based calculations without losing row-level details.


5️⃣ LAG & LEAD – Accessing Previous & Next Row Data

When comparing current vs. previous/future records, LAG & LEAD eliminate the need for self-joins.

SELECT name, salary, 
       LAG(salary) OVER (ORDER BY id) AS PreviousSalary,
       LEAD(salary) OVER (ORDER BY id) AS NextSalary
FROM Employees;

LAG() fetches the previous row’s value.
LEAD() fetches the next row’s value.

Ideal for trend analysis, financial reports, and comparative analytics.


6️⃣ RANK() vs. DENSE_RANK() – Choosing the Right Ranking

Both assign ranks, but they handle duplicates differently.

SELECT name, department, salary,
       RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS Rank,
       DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS DenseRank
FROM Employees;

RANK() skips numbers after duplicates. (eg. Rank - 1, 2, 2, 4, 5)
DENSE_RANK() assigns consecutive numbers. (eg. Rank - 1, 2, 2, 3, 4)

Use DENSE_RANK() when you don’t want ranking gaps.


7️⃣ JOIN vs. UNION – How They Differ

JOIN combines columns from multiple tables, while UNION stacks rows.

-- JOIN (Merging column data)
SELECT e.name, d.name FROM Employees e JOIN Departments d ON e.department_id = d.id;

-- UNION (Stacking results)
SELECT name FROM Employees UNION SELECT name FROM Contractors;

Use JOIN when you need more details from related tables.
Use UNION when you want to combine results from similar tables.


8️⃣ The Power of SUBSTRING() , STRING_AGG() , GROUP_CONCAT()

  • SUBSTRING() extracts parts of a string.

  • Both STRING_AGG and GROUP_CONCAT are used to concatenate multiple row values into a single string with a specified separator. However, there are some differences in syntax and capabilities.

SELECT SUBSTRING('Software Developer', 1, 8); -- Returns: 'Software'

SELECT 
    Class, 
    STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS StudentNames
FROM Students
GROUP BY Class;

SELECT 
    Class, 
    GROUP_CONCAT(Name ORDER BY Name ASC SEPARATOR ', ') AS StudentNames
FROM Students
GROUP BY Class;

✔ Great for data cleaning and reporting.


9️⃣ The Benefit of CTEs & Aliasing Subqueries

Common Table Expressions (CTEs) improve readability and avoid repeated subqueries.

WITH DepartmentCount AS (
    SELECT department_id, COUNT(*) AS EmployeeCount FROM Employees GROUP BY department_id
)
SELECT e.name, d.EmployeeCount FROM Employees e JOIN DepartmentCount d ON e.department_id = d.department_id;

✔ CTEs enhance query structure and avoid nested complexity.


🔟 Optimizing JOIN Conditions – AND vs. WHERE

Instead of filtering in WHERE, apply conditions in ON for better index usage.

-- Less efficient
SELECT e.name FROM Employees e JOIN Departments d ON e.department_id = d.id WHERE d.location = 'NY';

-- More efficient
SELECT e.name FROM Employees e JOIN Departments d ON e.department_id = d.id AND d.location = 'NY';

ON filters before the join happens, improving performance.


1️⃣1️⃣ Avoid SELECT * – Specify Columns

Fetching only required columns improves query speed.

-- Avoid this
SELECT * FROM Employees;

-- Do this instead
SELECT name, salary FROM Employees;

Reduces memory usage & speeds up query execution.


1️⃣2️⃣ SQL Execution Order –

Understanding execution order helps write optimized queries. The order is -

FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

SELECT department_id, COUNT(*)
FROM Employees
WHERE salary > 50000
GROUP BY department_id
HAVING COUNT(*) > 5;

✔ Queries execute in a different order than written. Hence, they should be written keeping in mind the execution order to improve performance. A useful mnemonic to remember SQL execution is:

"Fresh Juices With Great Healthy Sweet Orange Lemon"

  • Fresh → FROM

  • Juices → JOIN

  • With → WHERE

  • Great → GROUP BY

  • Healthy → HAVING

  • Sweet → SELECT

  • Orange → ORDER BY

  • Lemon → LIMIT


1️⃣3️⃣ Using LEFT() & RIGHT() for String Manipulation

SELECT LEFT('Developer', 3);  -- Returns 'Dev'
SELECT RIGHT('Database', 4);  -- Returns 'base'

✔ Great for handling text-based transformations.


Final Thoughts

Mastering these SQL techniques can significantly optimize queries, improve performance, and make your code cleaner and more maintainable. However, it’s important to note that SQL functions and behaviors can vary across different database engines.

For example:

  • GROUP_CONCAT is available in MySQL but not in SQL Server or PostgreSQL. Instead, they use STRING_AGG.

  • ISNULL is specific to SQL Server, whereas COALESCE is ANSI SQL-compliant and works across PostgreSQL, MySQL, and others.

  • LAG and LEAD are widely supported in modern databases but may have different implementations.

When working with SQL, always check the documentation of the specific database engine you’re using to ensure compatibility and take advantage of engine-specific optimizations.

👉 Which of these techniques have you used before? What other underrated SQL tricks have helped you? Let’s discuss!

Happy DevLogging! <3

#SQL #PerformanceTuning #DatabaseOptimization #BestPractices

0
Subscribe to my newsletter

Read articles from Samana Butool Mirza directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Samana Butool Mirza
Samana Butool Mirza

I am an aspiring developer with a creative flair for designing and a love for turning ideas into impactful solutions. From debugging code to crafting intuitive user experiences, I thrive on learning, growing, and sharing my journey in the ever-evolving tech world. When I’m not coding, you’ll find me exploring design tools, reading novels or...just sleeping.