Chapter 07 — Result Organization: Sorting & Limiting
1. What is it?
In relational database theory (Codd's Relational Model), tables are defined as mathematical sets: there is no inherent order to rows stored on disk. Unless an explicit ORDER BY clause is specified in your query, the order in which rows are returned by the storage engine is completely non-deterministic and can vary based on storage page fragmentation, parallel query execution, or cache state.
ORDER BY: Dictates the deterministic ordering of the returned result set based on one or more columns, expressions, or aliases, sorted in either ascending (ASC) or descending (DESC) order.LIMIT&OFFSET: Restricts the maximum number of rows streamed back to the client application, enabling UI pagination (e.g., displaying "20 items per page").LIMIT count: Returns at mostcountrows.LIMIT offset, count(or ANSI standardLIMIT count OFFSET offset): Skipsoffsetrows before beginning to return up tocountrows.
2. Why do we use it?
- Deterministic User Experience: Applications require predictable ordering—displaying top-rated products first, sorting leaderboard rankings, or displaying transactions chronologically.
- Resource Throttling & Pagination: Transferring 50,000 rows when a mobile screen only displays 25 wastes network bandwidth, exhausts client device memory, and delays render times.
- Top-N Business Analytics: Answering questions such as "Who are our 5 highest-earning employees?" or "What was yesterday's single largest order?" requires pairing
ORDER BYwithLIMIT 1orLIMIT N.
3. Syntax
SELECT column1, column2, ...
FROM table_name
[WHERE condition]
ORDER BY
column1 [ASC | DESC],
column2 [ASC | DESC],
...
LIMIT [offset,] row_count;
-- Alternative Standard ANSI SQL syntax for offset pagination:
-- LIMIT row_count OFFSET offset;Advanced Null Sorting Emulation in MySQL
In MySQL, NULL values are treated as physically lower than any non-NULL value. Consequently:
- In
ASCordering,NULLvalues appear first. - In
DESCordering,NULLvalues appear last.
To override this default and place NULL values last in an ascending sort:
-- Technique 1: Using boolean IS NULL (since TRUE=1, FALSE=0)
ORDER BY column_name IS NULL ASC, column_name ASC;
-- Technique 2: Using CASE expression
ORDER BY CASE WHEN column_name IS NULL THEN 1 ELSE 0 END, column_name ASC;4. Basic Example
Basic sorting and pagination queries:
USE sql_mastery;
-- Sort employees by salary descending (Highest paid first)
SELECT employee_id, first_name, last_name, salary
FROM employees
ORDER BY salary DESC;
-- Multi-column sorting: First by department_id ascending, then by salary descending
SELECT department_id, first_name, last_name, salary
FROM employees
ORDER BY department_id ASC, salary DESC;
-- Retrieve the top 3 highest-priced products
SELECT product_id, product_name, unit_price
FROM products
ORDER BY unit_price DESC
LIMIT 3;
-- UI Pagination: Page 2 (Skip first 3 products, fetch next 3)
SELECT product_id, product_name, unit_price
FROM products
ORDER BY unit_price DESC
LIMIT 3 OFFSET 3;5. Real-World Example
In our sql_mastery database, the finance director requires a prioritized report of all customer accounts:
- Customers must be sorted by
loyalty_pointsdescending. - In the event of ties in loyalty points, sort alphabetically by
last_nameascending, thenfirst_nameascending. - We need to display Page 1 of the executive dashboard, limited to the top 5 records.
- Any customer with a
NULLstate must be pushed to the bottom of the list without disrupting the loyalty hierarchy.
USE sql_mastery;
SELECT
customer_id,
first_name,
last_name,
city,
state,
country,
loyalty_points
FROM customers
ORDER BY
state IS NULL ASC, -- Guarantees customers with valid states appear before NULL states
loyalty_points DESC, -- Primary business sort
last_name ASC, -- Secondary tie-breaker
first_name ASC -- Tertiary tie-breaker
LIMIT 5 OFFSET 0;6. Step-by-Step Explanation
FROM customers: The engine accesses thecustomerstable.ORDER BYEvaluation:state IS NULL ASC: Evaluates the boolean expressionstate IS NULL. Ifstateis NOT null, this returns0. IfstateIS null, this returns1. Because0 < 1in ascending order, all customers with non-null states are grouped first!loyalty_points DESC: Within each state-nullability partition, the engine comparesloyalty_pointsin descending order, ranking customers with 940, 750, 610, etc., at the top.last_name ASC, first_name ASC: If two customers share the exact same loyalty point balance, MySQL breaks the tie by sorting alphabetically.
LIMIT 5 OFFSET 0: The engine's Filesort algorithm maintains a priority queue in memory (usingsort_buffer_size). Once the top 5 rows have been isolated, execution terminates immediately, avoiding the need to sort the remaining rows.
7. Expected Result
Output of the executive customer dashboard query:
+-------------+------------+-----------+---------------+-------+---------+----------------+
| customer_id | first_name | last_name | city | state | country | loyalty_points |
+-------------+------------+-----------+---------------+-------+---------+----------------+
| 3 | Sophia | Garcia | Miami | FL | USA | 750 |
| 5 | Aisha | Khan | Bengaluru | KA | India | 610 |
| 1 | Emily | Watson | San Francisco | CA | USA | 420 |
| 8 | Mateo | Silva | Sao Paulo | SP | Brazil | 290 |
| 2 | Michael | Brown | Austin | TX | USA | 180 |
+-------------+------------+-----------+---------------+-------+---------+----------------+
5 rows in set (0.00 sec)8. Common Mistakes
- Assuming Natural Table Order Exists:
- Mistake: Issuing
SELECT * FROM orders LIMIT 1;expecting to receive the "first" order ever created. - Correction: Without
ORDER BY order_date ASCorORDER BY order_id ASC, the engine can return any arbitrary row. Never rely on implicit physical ordering.
- Mistake: Issuing
- Confusing MySQL Comma Syntax (
LIMIT offset, count):- The Syntax Confusion:
- MySQL comma syntax:
LIMIT 10, 5means Skip 10 rows, return 5 rows. - ANSI standard syntax:
LIMIT 5 OFFSET 10means Return 5 rows, skip 10 rows.
- MySQL comma syntax:
- Beginners often write
LIMIT 10, 5thinking it means "Return rows 5 through 10". To prevent bugs, prefer the explicitLIMIT count OFFSET offsetsyntax.
- The Syntax Confusion:
- The "Deep Paging" Performance Trap:
- The Problematic Query:sql
SELECT * FROM orders ORDER BY order_date DESC LIMIT 20 OFFSET 1000000; - Catastrophic Performance: The engine cannot jump straight to row 1,000,000 on disk. It must scan, sort, and materialize all 1,000,020 rows through the sort buffer, only to discard the first 1,000,000 rows and return the final 20.
- The Professional Fix (Keyset / Cursor Pagination):sqlThis executes via an instant index seek.
-- Instead of OFFSET, filter using the last seen primary key / timestamp: SELECT * FROM orders WHERE order_id < 894520 ORDER BY order_id DESC LIMIT 20;
- The Problematic Query:
9. Best Practices
- Always Back
ORDER BY ... LIMITwith an Index:- If you frequently execute
SELECT * FROM orders ORDER BY order_date DESC LIMIT 10, build an index onorders(order_date). The engine reads the first 10 leaf entries from the B+ Tree in reverse order and finishes instantly, avoiding a full table scan and an in-memory Filesort.
- If you frequently execute
- Always Include a Deterministic Tie-Breaker:
- If sorting by a non-unique column (such as
order_dateorsalary), multiple rows may share identical values. Different database replicas or query invocations can return ties in differing sequences, causing records to skip or appear twice between paginated screens. Always append a unique tie-breaker:sqlORDER BY order_date DESC, order_id DESC
- If sorting by a non-unique column (such as
- Avoid Sorting by Raw Column Position Numbers:
- Avoid writing
ORDER BY 1, 3 DESC;. If someone later alters theSELECTcolumn list or adds a column, the query will silently sort by the wrong fields, causing subtle logic bugs. Always write explicit column names.
- Avoid writing
10. Practice Questions
Easy
- Write a query to list all products ordered from least expensive to most expensive.
- Write a query to retrieve the 5 most recently hired employees from the
employeestable. - Write a query to fetch the single most expensive product in category 1.
Medium
- Write a query to return rows for Page 3 of an employee directory, where each page contains 4 employees, sorted alphabetically by
last_nameascending. - Write a query that selects all customers, sorting them so that customers residing in
'USA'appear at the top, and all other countries appear below them sorted alphabetically. - Write a query retrieving
order_id,order_date, andtotal_amount, sorted bytotal_amountdescending, skipping the top 2 highest orders and returning the next 3.
Difficult
- Write a query against the
employeestable that sorts records bydepartment_idascending, with all employees who have aNULLdepartment placed strictly at the end, and ties within each department broken bysalarydescending. - Explain what an
Using filesortnote indicates in a MySQLEXPLAINexecution plan for anORDER BYquery. How can creating an index eliminate this overhead?
11. Interview Questions
Q1: What is the "Deep Paging Problem" with LIMIT offset, count, and how do you solve it in production?
Answer: In relational databases, LIMIT 1000000, 20 requires the storage engine to physically scan and process 1,000,020 rows, buffering them through memory and discarding the first 1,000,000 rows to deliver the final 20. This wastes substantial I/O, CPU, and memory, and query execution time scales linearly with offset size. The production solution is Keyset Pagination (or Cursor-based Pagination). Instead of using numeric offsets, the client application tracks the unique identifier (or timestamp) of the last seen record from the current page and requests the next page via a direct indexed filter: WHERE order_id < last_seen_order_id ORDER BY order_id DESC LIMIT 20. This uses an index seek and executes in constant $O(1)$ time regardless of page depth.
Q2: How does MySQL handle NULL values when executing an ORDER BY statement?
Answer: MySQL considers NULL values to be lower in magnitude than any non-NULL value. Under ORDER BY column ASC, all NULL values are grouped together at the very beginning of the result set. Under ORDER BY column DESC, all NULL values appear at the very end. To alter this behavior (for example, to display NULLs last in an ascending sort), you can use an explicit boolean expression such as ORDER BY column IS NULL ASC, column ASC.
Q3: What is the difference between sorting via an index seek versus sorting via a Filesort in MySQL?
Answer:
- Index-based Ordering: When an index exists on the sorting columns matching the query's
ORDER BYspecifications, the engine navigates the B+ Tree sequentially. The data is already physically ordered, allowing MySQL to stream rows immediately without any in-memory sorting. - Filesort: When no suitable index exists, MySQL must extract candidate rows meeting the
WHEREcriteria into memory (sort_buffer_size) and perform an explicit sorting algorithm (typically quicksort or merge sort). If the candidate dataset exceeds the allocated buffer size, temporary sort files are written to disk, introducing severe disk I/O bottlenecks.
12. Quick Revision
- Relational tables have no default order; deterministic results require an explicit
ORDER BYclause. ASCsorts from smallest to largest;DESCsorts from largest to smallest.- In MySQL,
NULLis sorted as the smallest possible value (first inASC, last inDESC). - Use
LIMIT count OFFSET offsetfor UI pagination. - Avoid large numeric offsets (the Deep Paging Problem); prefer Keyset Pagination for high-volume datasets.
- Always append a unique tie-breaker column (such as the Primary Key) to guarantee stable, deterministic sorting across pages.