Rowstore vs Columnstore Index
See how columnstore stores data column by column, how it is built (row groups, segments, compression) and when to use it over rowstore.
Two very different kinds of query hit an IPL database. The app asks "show me Virat Kohli's full profile" — one complete row. The analyst asks "total runs of every team over 15 seasons of ball-by-ball data" — one or two columns from hundreds of millions of rows. Storing data row by row is perfect for the first; storing it column by column is perfect for the second.
Definition
A rowstore index stores data row by row: each page holds complete rows (id, name, team, runs together). This is the traditional format and the default in SQL Server.
A columnstore index stores data column by column: values of one column are kept together in compressed segments, so a query reads only the columns it needs.
- Row by row → great when you need the whole record (OLTP: orders, banking, bookings).
- Column by column → great when you scan and aggregate a few columns over huge tables (OLAP: data warehouses, BI, reports).
- Compressed segments → a column like
teamhas very few distinct values (RCB, MI, CSK …), so it compresses extremely well.
Rowstore vs Columnstore — the picture
| Rowstore page | Columnstore segment |
|---|---|
page 1: Kohli, RCB | segment name: Kohli, Sharma, Buttler, Dhoni |
page 2: Sharma, MI | segment team: RCB, MI, RR, CSK |
page 3: Buttler, RR | segment runs: 750, 500, 850, 350 |
page 4: Dhoni, CSK | segment id: 1, 2, 3, 4 |
| each page holds complete rows | each segment holds one column |
How a columnstore index is built — 4 steps
| Step | What happens |
|---|---|
| 1. Row groups | The table is cut into groups of about 1 million rows (max 1,048,576). |
| 2. Column segments | Each row group is split by column — one segment per column. |
| 3. Compress | Each segment is compressed with dictionary + run-length encoding (e.g. "MI, MI, MI, MI" → "MI × 4"). |
| 4. Store | The compressed segments are saved as LOB pages. |
Result: SELECT COUNT(*) FROM players WHERE team = 'MI' reads only the team segment — not the whole table. Small new inserts first land in a rowstore delta store and are compressed into a row group later.
Rowstore vs Columnstore — comparison
| Rowstore | Columnstore | |
|---|---|---|
| Definition | Stores data row by row | Stores data column by column |
| Storage efficiency | Less efficient | Highly efficient (heavy compression) |
| Read / write | Fair speed for both | Fast reads, slow writes |
| I/O efficiency | Lower — reads all columns of a row | Higher — reads only the needed columns |
| Best for | OLTP: orders, banking, bookings | OLAP: data warehouses, BI, reporting |
| Use case | Many small transactions on whole records | Scanning huge tables, fast aggregation |
Syntax
sql
CREATE [CLUSTERED | NONCLUSTERED] [COLUMNSTORE] INDEX index_name
ON table_name (column1, column2, ...);| Part | Meaning |
|---|---|
COLUMNSTORE | store the index column by column. Leave it out → rowstore (the default) |
CLUSTERED COLUMNSTORE | the whole table becomes columnstore — no column list allowed |
NONCLUSTERED COLUMNSTORE | a columnstore copy of the chosen columns, while the table stays rowstore |
Example — a big analytics table of every ball bowled
sql
-- The whole ball_by_ball table is stored column by column
CREATE CLUSTERED COLUMNSTORE INDEX CCI_ball_by_ball
ON ball_by_ball;
-- Rowstore table, plus a columnstore copy of two columns for reports
CREATE NONCLUSTERED COLUMNSTORE INDEX NCCI_innings_team_runs
ON innings (team, runs);How it works: after the first statement, a report such as SELECT team, SUM(runs) FROM ball_by_ball GROUP BY team reads just the compressed team and runs segments and is processed in batch mode (thousands of rows at a time) — often 10× or more faster than rowstore on very large tables.
Rule: you cannot choose columns for a CLUSTERED columnstore index — it always covers the whole table. A table can have only one columnstore index.
Common mistakes
- ❌ Adding a columnstore index to a busy OLTP table with constant single-row updates. ✅ Use it for read-heavy analytics; writes are slow.
- ❌ Writing
CREATE CLUSTERED COLUMNSTORE INDEX CCI ON t (col1, col2). ✅ Clustered columnstore takes no column list. - ❌ Expecting a gain on a 10,000-row table. ✅ Columnstore shines at millions of rows (a row group is ~1M rows).
SQL Server vs others
Columnstore indexes are a SQL Server (and Azure SQL) feature. MySQL and PostgreSQL don't have a built-in equivalent (analytics engines like ClickHouse, Redshift, Snowflake and BigQuery are columnar by design). The playground (SQLite) has no columnstore at all.
Interview tip
Q: When would you use a columnstore index instead of a rowstore index? A: For analytical (OLAP) workloads — large fact tables that are scanned and aggregated on a few columns. Columnstore reads only the needed columns, compresses heavily and uses batch mode. For transactional (OLTP) workloads that read and write whole rows, rowstore is better.
Key points to remember
- Rowstore stores complete rows on each page — the default, best for OLTP (whole records, many small writes).
- Columnstore stores each column in its own compressed segment — best for OLAP (scan and aggregate a few columns over huge tables).
- Columnstore is built in 4 steps: ~1M-row row groups → one segment per column → dictionary/run-length compression → stored as LOB pages.
- A query on a columnstore reads only the segments of the columns it uses.
- CLUSTERED COLUMNSTORE covers the whole table and takes no column list; NONCLUSTERED COLUMNSTORE covers chosen columns.
- Columnstore = fast reads, slow writes; the default when you omit COLUMNSTORE is rowstore.
Try it yourself
SQL Server: clustered and non-clustered columnstore
-- Whole table stored column by column (no column list allowed)
CREATE CLUSTERED COLUMNSTORE INDEX CCI_ball_by_ball
ON ball_by_ball;
-- Rowstore table + a columnstore copy of two columns for reports
CREATE NONCLUSTERED COLUMNSTORE INDEX NCCI_innings_team_runs
ON innings (team, runs);SQL Server-specific — run this in SQL Server (SSMS / Azure Data Studio).
Try it: the kind of query columnstore is built for
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Practice: OLTP vs OLAP query
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Revision Flashcards
Tap a card to flip it and see the answer.
