One of SQLite’s unique features is the WITHOUT ROWID
table, which can be used to optimize performance and storage in specific scenarios.
While it’s easy enough to create a WITHOUT ROWID
table (just add WITHOUT ROWID
to the definition), how to identify a WITHOUT ROWID
table might not be so obvious.
In this article, we’ll start by briefly revising what WITHOUT ROWID
tables are and how they differ from ordinary tables. Then we’ll look at how to identify these tables by using SQLite’s PRAGMA commands.
What is a WITHOUT ROWID
Table?
By default, SQLite assigns a unique ROWID
to every row in a table, even if the table has a separate PRIMARY KEY
. This allows rows to be indexed and accessed by their ROWID
.
We can leverage the ROWID
for our primary key by defining a column as INTEGER PRIMARY KEY
. When we do that, the column becomes an alias for ROWID
. Therefore, we don’t need to insert separate values into the primary key column. We can simply use the existing ROWID
that’s automatically generated by SQLite.
But if we define the table as WITHOUT ROWID
, we no longer get the implicit ROWID
. Instead, the table’s PRIMARY KEY
becomes the sole mechanism for indexing and organizing rows. This can result in:
- Better performance for tables with natural primary keys.
- Reduced storage overhead because there’s no need for a separate
ROWID
.
However, the decision to define a table as WITHOUT ROWID
shouldn’t be taken lightly. In many cases, you might be better off leveraging the ROWID
. This should be a case-by-case decision, taking into account the data that each table will store, and how it will be used.
The Role of PRAGMAs in SQLite
SQLite offers PRAGMA commands as a way to inspect and modify database settings. Two useful PRAGMAs for understanding table structures are:
PRAGMA table_info
: Displays the columns in a table, including their names, types, and constraints.PRAGMA table_xinfo
: Similar totable_info
, but it also includes hidden columns (used in virtual tables).
However, these PRAGMAs alone don’t reveal whether a table is a WITHOUT ROWID
table.
Identifying a WITHOUT ROWID
Table Using PRAGMA index_info
The key to identifying a WITHOUT ROWID
table lies in the PRAGMA index_info
command. Normally, this PRAGMA is used to examine the details of an index on a table, such as the columns included in the index.
Here’s the important distinction:
- For ordinary tables,
PRAGMA index_info
returns no rows if no explicit index exists. - For
WITHOUT ROWID
tables,PRAGMA index_info
always returns information about the table’sPRIMARY KEY
, even though no separate index was explicitly created.
This behavior provides a reliable way to determine if a table is WITHOUT ROWID
. If PRAGMA index_info
returns rows for the table’s primary key, you can conclude it’s a WITHOUT ROWID
table.
Example: Comparing Ordinary and WITHOUT ROWID
Tables
Let’s walk through an example to see this in action.
1. Create Two Tables
Let’s create an ordinary table and a WITHOUT ROWID
table with similar structures:
-- Ordinary table
CREATE TABLE ordinary_table (
id INTEGER PRIMARY KEY,
name TEXT
);
-- WITHOUT ROWID table
CREATE TABLE without_rowid_table (
id INTEGER PRIMARY KEY,
name TEXT
) WITHOUT ROWID;
2. Use PRAGMA Commands
Inspect Table Columns
Let’s first use the PRAGMA table_info
and PRAGMA table_xinfo
commands to inspect the tables’ columns:
PRAGMA table_info('ordinary_table');
PRAGMA table_xinfo('ordinary_table');
PRAGMA table_info('without_rowid_table');
PRAGMA table_xinfo('without_rowid_table');
Output:
cid name type notnull dflt_value pk
--- ---- ------- ------- ---------- --
0 id INTEGER 0 1
1 name TEXT 0 0
cid name type notnull dflt_value pk hidden
--- ---- ------- ------- ---------- -- ------
0 id INTEGER 0 1 0
1 name TEXT 0 0 0
cid name type notnull dflt_value pk
--- ---- ------- ------- ---------- --
0 id INTEGER 1 1
1 name TEXT 0 0
cid name type notnull dflt_value pk hidden
--- ---- ------- ------- ---------- -- ------
0 id INTEGER 1 1 0
1 name TEXT 0 0 0
Both tables return the same result.
Inspect Index Information
Running PRAGMA index_info
reveals the difference:
PRAGMA index_info('ordinary_table');
This command returns no rows for the ordinary table.
Let’s run it on the WITHOUT ROWID
table:
PRAGMA index_info('without_rowid_table');
For the WITHOUT ROWID
table, this command returns:
seqno cid name
----- --- ----
0 0 id
This output indicates that the PRIMARY KEY
acts as the index for the WITHOUT ROWID
table.
Why Does This Matter?
Knowing whether a table is WITHOUT ROWID
can be useful when optimizing for performance or troubleshooting. The distinction affects how rows are stored and indexed, which can impact query execution time and storage efficiency.
The PRAGMA index_info
command provides a simple, unambiguous way to determine the table type.
Conclusion
SQLite’s WITHOUT ROWID
tables offer performance and storage benefits for certain use cases. Understanding how to identify these tables using PRAGMA commands—especially PRAGMA index_info
—empowers you to make informed decisions about your database design and maintenance.