The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Database
What is an index, and what changes when there is none?
An index is a list that keeps the values of a column in order and points to the rows that hold each value. The database builds it separately from the table, and it works like the index at the back of a book. CREATE INDEX idx_name ON member(name) is the statement that builds an index on the name column. Without an index, the database has to read the rows of the table from the first to the last to find the rows that match a condition. With an index, it looks up the value in the index and reads only the rows it needs. In this lab, you remove CREATE INDEX or change the column you search by, run the same SELECT, and see how the number of rows the database reads changes even though the rows it finds stay the same. This lab does not cover how an index organizes its values or what it costs to build one.
Checked against real execution · Ran all 6 combinations on H2 2.4.240 and checked them (rows read is scanCount minus 1 from EXPLAIN ANALYZE), and checked the rules against the MySQL documentation
CREATE TABLE member (
id INT PRIMARY KEY,
name VARCHAR(20),
city VARCHAR(20)
);
-- Insert 1000 members (user1 to user1000. The INSERT statements are omitted on the screen)
-- Index: build an index so that rows can be found quickly by the name value
CREATE INDEX idx_name ON member(name);
SELECT * FROM member WHERE name = 'user777';
It was run and checked against H2 2.4.240 (in-memory database, JDBC). It ran all 6 combinations, and it ran the whole SQL on the screen, including the comment lines, exactly as written. At the "Insert 1000 members" comment line on the screen, the verification program inserted 1000 members (ids 1 to 1000, names user1 to user1000, and 250 members each for the cities Seoul, Busan, Daegu, and Gwangju, in turn), and the INSERT statements are omitted on the screen. What it checked is the number of rows the SELECT returned, how H2 EXPLAIN said it would search (the name index IDX_NAME, the primary key index PRIMARY_KEY, and tableScan with no index), the scanCount that EXPLAIN ANALYZE reported, and the facts that the step sentences rely on. The facts they rely on are that the index on the id column exists automatically right after CREATE TABLE, that CREATE INDEX built an index with the name column in order, that the table still has 1000 rows before and after CREATE INDEX, and that the SELECT returns the same rows with and without an index. The "Rows the database read" on the screen is scanCount minus 1. The H2 documentation does not define what scanCount means, and in this version the scanCount we observed is 1 more than the number of rows read (it looks like one more is added to confirm that there are no more rows to read). The evidence is this. When we read a table with 0, 10, and 1000 rows from start to finish, scanCount was 1, 11, and 1001. When we forced a full read by using a function that counts how many times it is called per row in the condition, the function was called 1000 times and scanCount was 1001. When we looked up a value that does not exist by an index, scanCount was 1, and for a value that exists, it was 2. Following this observation, the "1 row" for a search by index is also the value with 1 subtracted in the same way, and it equals the number of rows found. The database decides how to search by looking at the amount and distribution of the data, so on another database or with other data it may not use an index even if there is one. This is the result observed with this data in H2 on the PC used to write this lab. We opened the H2 documentation, on the performance page, "How Data is Stored and How Indexes Work" (an index is like a table with the indexed columns and the row number) and "Statement Execution Plans (EXPLAIN)" (EXPLAIN ANALYZE shows the rows read, tableScan means that no index was used, and an index is created automatically for a primary key and a unique constraint), and checked against it. We opened the MySQL 8.4 documentation, section 10.3.1 How MySQL Uses Indexes (without an index, it has to read the whole table from the first row), section 15.1.15 CREATE INDEX Statement (it adds an index to an existing table), section 10.3.2 Primary Key Optimization (a primary key has an index attached), and the PRIMARY KEY item of the CREATE TABLE statement, and checked against them. However, we did not check against execution on MySQL. Also, this screen draws the index of the primary key as a box like the name index, but H2 and MySQL (InnoDB) use an integer primary key as the sort order of the table data itself, so the index of the primary key is not a list separate from the table like the name index. We did not cover the structure of an index (B-tree and so on), or the cost that comes from INSERT, UPDATE, and DELETE having to update the index as well when an index exists. The in-depth lab "Indexes and full table scans" covers them.
Previous lab: GROUP BY and aggregation · Next lab: Transactions
Struck-through text was removed from the first version of the code; highlighted text was added.