B-Tree Index with order
Introduction
- When initializing a
B-Tree Index, it also allows the option to choose the data sorting direction, includingASC (default) and DESC - This feature is uniquely supported for
B-Tree Indexonly, you cannot use it for otherIndextypes (GIN, GiST, BRIN,...) - The reason is due to the tree structure ordering keys, which can be read forward or backward to retrieve sorted results
- Other
Indextypes do not support storing sorted data, they are used to serve specific data types and problems, sorting data orderORDER BYis not in their core design.
NULL value
- In Postgres,
NULLis understood as anUnknownvalue and is always considered greater than any normal value. - Therefore, by default:
- When you create an
ASC Index(Ascending):NULLvalues are at the END (NULLS LAST). - When you create a
DESC Index(Descending): SinceNULLis the largest, when sorting from high to low, NULL will be at the BEGINNING (NULLS FIRST).
- When you create an
Use case
Includes forms such as
CREATE INDEX idx_column_desc ON posts (column ASC): ASC can be omitted, then default data in the index is also sorted ascendingCREATE INDEX idx_column_desc ON posts (column DESC): sorted descending- In addition, you can use
NULLS FIRSTorNULLS LASTto create more variations to sort NULL values to suit your needsCREATE INDEX idx_column_desc ON posts (column ASC NULLS FIRST): sorted ascending and NULL is at the endCREATE INDEX idx_column_desc ON posts (column DESC NULLS LAST): sorted descending and NULL is at the top
Notes
- If you only create an Index on 1 column, whether you create an
ASCorDESCIndex, you can query in the reverse direction and the Index still works - If creating a
Composite Index, it is still based on that principle but you must pay attention to the usage order of columns, you can see specifics in this article - As for the
NULLvalue, the Index only works if querying in the exact order as when created, otherwise Postgres must use a less efficient solution,Seq Scan, and resort the data
Detail
First, create a table as follows
CREATE TABLE users (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
phone_number VARCHAR(20) NULL,
status VARCHAR(20) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Then you can optionally select Index types like this
-- Query 1
CREATE INDEX idx_users_phone_number ON users(phone_number);
CREATE INDEX idx_users_phone_number ON users(phone_number ASC NULLS LAST);
-- Query 2
CREATE INDEX idx_users_phone_number ON users(phone_number DESC);
CREATE INDEX idx_users_phone_number ON users(phone_number DESC NULLS FIRST);
-- Query 3
CREATE INDEX idx_users_phone_number_asc_nulls_first ON users(phone_number ASC NULLS FIRST);
CREATE INDEX idx_users_phone_number_desc_nulls_last ON users(phone_number DESC NULLS LAST);
- Query 1: When using
users(phone_number), the default is ascending sort and NULL values are placed last, so its full query will beusers(phone_number ASC NULLS LAST) - Query 2: When using
users(phone_number DESC), the default is descending sort and NULL values are placed first, so its full query will beusers(phone_number DESC NULLS FIRST) - Query 3: This is how to create Indexes in the reverse direction including
ASC NULLS FIRSTandDESC NULLS LAST
Next is checking Index operation
-- Query 1
SELECT * FROM users ORDER BY phone_number LIMIT 10
SELECT * FROM users ORDER BY phone_number ASC NULLS LAST LIMIT 10
-- Query 2
SELECT * FROM users ORDER BY phone_number DESC LIMIT 10
SELECT * FROM users ORDER BY phone_number DESC NULLS FIRST LIMIT 10
-- Query 3
SELECT * FROM users ORDER BY phone_number ASC NULLS FIRST LIMIT 10
SELECT * FROM users ORDER BY phone_number DESC NULLS LAST LIMIT 10
Query 1: Both of these queries are ASC NULLS LAST, you need to add LIMIT to trigger the Index, because if retrieving all table data, Postgres will choose to use Seq Scan
Query 2: Both of these queries are DESC NULLS FIRST, even if you do not create an Index for DESC, Postgres will automatically know how to fetch data backwards from ASC
Query 3: These are 2 queries that will sort in the opposite direction, ASC NULLS FIRST and DESC NULLS LAST, which default does not support
ASC NULLS FIRST: Default only hasASC NULLS LAST, if there is no Index, it must use Seq Scan to sort ascending and then put NULL values at the topDESC NULLS LAST: Default only hasDESC NULLS FIRST, if there is no Index, it must use Seq Scan to sort descending and then put NULL values at the bottom- Even if you do not create an Index for
DESC NULLS LAST, Postgres knows how to retrieve data backwards from theASC NULLS FIRSTIndex - You can check before and after adding the Index to see the difference
Before adding Index
After adding Index
Happy coding!
Comments
Post a Comment