LeetCode SQL Optimization: Window Functions vs. Subqueries
Developers who frequently use LeetCode are certainly familiar with the problem 185: Department Top Three Salaries, a classic question included in the Top SQL 50. The official provides two reference solutions, which can be found at: Official Solution. These two approaches have sparked extensive discussions in the LeetCode comment section. Let’s conduct a practical test to compare the differences between these two correct answers under real-world data scenarios.
This solution uses correlated subqueries to determine the salary ranking row by row. It calculates the number of employees in the same department with higher salaries than the current employee. If the count is less than 3, the record is retained.
Solution 2: Window Function Approach (Modern Method)
This solution leverages the DENSE_RANK() window function to rank employees by descending salary within each department and directly filters records ranked in the top 3.
Performance Testing: Battle of Queries with Ten Thousand-Level Data
Let’s conduct a performance test of these two solutions.
Table:Employee+--------------+---------+
|ColumnName|Type|+--------------+---------+
|id|int||name|varchar||salary|int||departmentId|int|+--------------+---------+
idistheprimarykeyforthistable.departmentIdisaforeignkeyreferencingtheIDcolumnoftheDepartmenttable.Eachrowindicatesanemployee's ID, name, salary, and department ID.
Table: Department
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
+-------------+---------+
id is the primary key for this table.
Each row indicates a department'sIDandname.
Table Creation Statements:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Create Department table
CREATETABLEDepartment(idINTPRIMARYKEY,nameVARCHAR(100));-- Create Employee table
CREATETABLEEmployee(idINTPRIMARYKEY,nameVARCHAR(100),salaryINT,departmentIdINT,FOREIGNKEY(departmentId)REFERENCESDepartment(id));
Stored Procedure:
This stored procedure creates 10 departments and inserts 1,000 employees into each department, resulting in a total of 10,000 Employee records.
The performance difference turned out to be significant. The SQL using DENSE_RANK() executed in milliseconds, while the subquery version took over 5 seconds, which is unacceptable.
Why Use Window Functions?
Starting from MySQL version 8.0, window functions were introduced, greatly enhancing complex analysis capabilities in SQL. Compared to traditional methods like subqueries or temporary tables, window functions offer the following advantages:
Avoid Repeat Scans and Multiple Calculations: Traditional methods like subqueries often require multiple table scans, especially for calculations like ranking or cumulative sums, which can lead to performance bottlenecks. Window functions complete multiple calculations in a single scan.
Reduce Intermediate Results and Temporary Table Overheads: Subqueries or JOINs typically generate intermediate result sets, potentially requiring temporary tables or worktables, increasing memory and disk usage.
Avoid Unnecessary Materialization: Window functions share computation results under the same PARTITION BY and ORDER BY conditions, avoiding repeated calculations.
SQL Optimization with SQLFLASH
Although there are differences in SQL syntax, the results remain consistent. It seems that SQLFlash can easily handle it!
Summary and Recommendations
Prioritize window functions: In MySQL 8.0+ or databases that support window functions, they are the superior choice.
SQLFlash is your AI-powered SQL Optimization Partner.
Based on AI models, we accurately identify SQL performance bottlenecks and optimize query performance, freeing you from the cumbersome SQL tuning process so you can fully focus on developing and implementing business logic.