YSQL – Verify Secondary Index Usage

The use of secondary indexes can enhance database performance by enabling the database server to find rows faster.

If you create too many indexes on a table, you may start see a performance degradation on INSERTs into the table.

It’s important to periodically check to see if your indexes are actually being used for your work load.  

We can query the pg_stat_user_indexes system table to determine if an index has been scanned. 

Example:

				
					yugabyte=> CREATE TABLE test (c1 INT, c2 VARCHAR, c3 VARCHAR);
CREATE TABLE

yugabyte=> INSERT INTO test SELECT 1, 'A', 'X';
INSERT 0 1

yugabyte=> INSERT INTO test SELECT 2, 'B', 'Y';
INSERT 0 1

yugabyte=> INSERT INTO test SELECT 3, 'C', 'Z';
INSERT 0 1

yugabyte=> CREATE INDEX test_c2_idx ON test(c2);
CREATE INDEX

yugabyte=> CREATE INDEX test_c3_idx ON test(c3);
CREATE INDEX

yugabyte=> SELECT indexrelname, idx_scan FROM pg_stat_user_indexes WHERE relname = 'test';
 indexrelname | idx_scan
--------------+----------
 test_c2_idx  |        0
 test_c3_idx  |        0
(2 rows)
				
			

Let’s run a query that uses the test_c2_idx

				
					yugabyte=> EXPLAIN SELECT c2 FROM test WHERE c2 = 'A';
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Index Only Scan using test_c2_idx on test  (cost=0.00..5.12 rows=10 width=32)
   Index Cond: (c2 = 'A'::text)
(2 rows)

yugabyte=> SELECT c2 FROM test WHERE c2 = 'A';
 c2
----
 A
(1 row)

yugabyte=> SELECT indexrelname, idx_scan FROM pg_stat_user_indexes WHERE relname = 'test';
 indexrelname | idx_scan
--------------+----------
 test_c2_idx  |        1
 test_c3_idx  |        0
(2 rows)

yugabyte=> SELECT c2 FROM test WHERE c2 = 'A';
 c2
----
 A
(1 row)

yugabyte=> SELECT indexrelname, idx_scan FROM pg_stat_user_indexes WHERE relname = 'test';
 indexrelname | idx_scan
--------------+----------
 test_c2_idx  |        2
 test_c3_idx  |        0
(2 rows)
				
			

Note that each time I ran the query, the idx_scan column count increased.

Now let’s try the test_c3_idx

				
					yugabyte=> EXPLAIN SELECT * FROM test WHERE c3 = 'X';
                                QUERY PLAN
--------------------------------------------------------------------------
 Index Scan using test_c3_idx on test  (cost=0.00..5.22 rows=10 width=68)
   Index Cond: ((c3)::text = 'X'::text)
(2 rows)

yugabyte=> SELECT * FROM test WHERE c3 = 'X';
 c1 | c2 | c3
----+----+----
  1 | A  | X
(1 row)

yugabyte=> SELECT indexrelname, idx_scan FROM pg_stat_user_indexes WHERE relname = 'test';
 indexrelname | idx_scan
--------------+----------
 test_c2_idx  |        2
 test_c3_idx  |        1
(2 rows)
				
			

Have Fun!

River Walk, Bradenton, FL