< Day Day Up > |
13.1 Index Optimization and Index UsageWhen you create a table, consider whether it should have indexes, because they have important benefits:
13.1.1 Types of IndexesMySQL supports four types of indexes:
To define indexes when you're initially creating a table, use CREATE TABLE. To add indexes to an already existing table, use ALTER TABLE or CREATE INDEX. To drop indexes, use ALTER TABLE or DROP INDEX. ALTER TABLE can add or drop several indexes in the same statement, which is faster than processing each one separately. CREATE INDEX and DROP INDEX allow only one index to be added or dropped at a time. Index creation using the INDEX, UNIQUE, and PRIMARY KEY keywords is discussed in the "Core Study Guide." FULLTEXT indexes are not covered there because they are a more specialized kind of index. Instead, FULLTEXT indexing is discussed in section 13.1.4, "FULLTEXT Indexes Indexes." 13.1.2 Obtaining Table Index InformationTo find out what indexes a table has, use SHOW CREATE TABLE to display the CREATE TABLE statement that corresponds to the table structure, including its indexes. For more detailed information about the indexes, use SHOW INDEX. For example, SHOW INDEX produces the following output for the Country table of the world database:
mysql> SHOW INDEX FROM Country\G
*************************** 1. row ***************************
Table: Country
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: Code
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
The output indicates that the table has a single index, a primary key on the Code column. The output for the City table is similar except that it indicates the ID column is the primary key:
mysql> SHOW INDEX FROM City\G
*************************** 1. row ***************************
Table: City
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: ID
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
For the CountryLanguage table, the output has two rows because the primary key includes two columns, Country and Language:
mysql> SHOW INDEX FROM CountryLanguage\G
*************************** 1. row ***************************
Table: CountryLanguage
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: Country
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
*************************** 2. row ***************************
Table: CountryLanguage
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 2
Column_name: Language
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
The Seq_in_index values show the order of the columns within the index. They indicate that the primary key columns are Country first and Language second. This information corresponds to the following PRIMARY KEY declaration: PRIMARY KEY (Country, Language) 13.1.3 Using IndexesAn index helps MySQL perform retrievals more quickly than if no index is used. But indexes can be used with varying degrees of success, so you should keep several index-related considerations in mind when designing tables:
13.1.3.1 Indexing Column PrefixesShort index values can be processed more quickly than long ones. Therefore, when you index a column, it's worth asking whether it's sufficient to index partial column values rather than complete values. This technique, known as indexing a column prefix, can be applied to string column types. Suppose that you're considering creating a table using this definition: CREATE TABLE t ( name CHAR(255), INDEX (name) ); If you index all 255 bytes of the values in the name column, index processing will be relatively slow:
It's often possible to overcome these problems by indexing only a prefix of the column values. For example, if you expect column values to be distinct most of the time in the first 15 bytes, index only that many bytes of each value, not all 255 bytes. To specify a prefix length for a column, follow the column name in the index definition by a number in parentheses. The following table definition is the same as the previous one, except that the index uses just the first 15 bytes of each column value: CREATE TABLE t ( name CHAR(255), INDEX (name(15)) ); Indexing a column prefix can speed up query processing, but works best when the prefix values tend to have about the same amount of uniqueness as the original values. Don't use such a short prefix that you produce a very high frequency of duplicate values in the index. It might require some testing to find the optimal balance between long index values that provide good uniqueness versus shorter values that compare more quickly but have more duplicates. To determine the number of records in the table, the number of distinct values in the column, and the number of duplicates, use this query: SELECT COUNT(*) AS 'Total Rows', COUNT(DISTINCT name) AS 'Distinct Values', COUNT(*) - COUNT(DISTINCT name) AS 'Duplicate Values' FROM t; That gives you an estimate of the amount of uniqueness in the name values. Then run a similar query on the prefix values: SELECT COUNT(DISTINCT LEFT(name,n)) AS 'Distinct Prefix Values', COUNT(*) - COUNT(DISTINCT LEFT(name,n)) AS 'Duplicate Prefix Values' FROM t; That tells you how the uniqueness characteristics change when you use an n-byte prefix of the name values. Run the query with different values of n to determine an acceptable prefix length. Note that when an index on a full column is a PRIMARY KEY or UNIQUE index, you might have to change the index to be nonunique if you decide to index prefix values instead. If you index partial column values and require the index to be unique, that means the prefix values must be unique, too. 13.1.3.2 Leftmost Index PrefixesIn a table that has a composite (multiple column) index, MySQL can use leftmost index prefixes of that index. A leftmost prefix of a composite index consists of one or more of the initial columns of the index. MySQL's capability to use leftmost index prefixes enables you to avoid creating unnecessary indexes. The CountryLanguage table in the world database provides an example of how a leftmost prefix applies. The table has a two-part primary key:
mysql> SHOW INDEX FROM CountryLanguage\G
*************************** 1. row ***************************
Table: CountryLanguage
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: CountryCode
Collation: A
Cardinality: 246
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
*************************** 2. row ***************************
Table: CountryLanguage
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 2
Column_name: Language
Collation: A
Cardinality: 984
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
The index on the CountryCode and Language columns allows records to be looked up quickly based on a given country name and language. However, MySQL also can use the index given just a country code. Suppose that you want to determine which languages are spoken in France: SELECT * FROM CountryLanguage WHERE CountryCode = 'FRA'; MySQL can see that CountryCode is a leftmost prefix of the primary key and use it as though it were a separate index. This means there's no need to define a second index on the CountryCode column alone. On the other hand, if you want to perform indexed searches using just the Language column of the CountryLanguage table, you do need to create a separate index because Language is not a leftmost prefix of the existing index. Note that a leftmost prefix of an index and an index on a column prefix are two different things. A leftmost prefix of an index consists of leading columns in a multiple-column index. An index on a column prefix indexes the leading bytes of values in the column. 13.1.4 FULLTEXT IndexesFULLTEXT indexes are designed to make text searching fast and easy. They have the following characteristics:
To perform a FULLTEXT search, use MATCH and AGAINST(). For example, to search the table t for records that contain 'Wendell' in the name column, use this query: SELECT * FROM t WHERE MATCH(name) AGAINST('Wendell'); The MATCH operator names the column or columns you want to search. As mentioned earlier, there must be a FULLTEXT index on exactly those columns. If you want to search different sets of columns, you'll need one FULLTEXT index for each set. If a table people has name and address columns and you want to search them either separately or together, three FULLTEXT indexes are needed: CREATE TABLE people ( name CHAR(40), address CHAR(40), FULLTEXT (name), # index for searching name only FULLTEXT (address), # index for searching address only FULLTEXT (name,address) # index for searching name and address ); The indexes allow queries such as the following to be formulated: SELECT * FROM people WHERE MATCH(name) AGAINST('string'); SELECT * FROM people WHERE MATCH(address) AGAINST('string'); SELECT * FROM people WHERE MATCH(name,address) AGAINST('string'); The preceding discussion summary of FULLTEXT indexing and searching is very brief. More information may be found in the MySQL Reference Manual. |
< Day Day Up > |