{"id":103897,"date":"2024-09-11T03:43:53","date_gmt":"2024-09-11T03:43:53","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=103897"},"modified":"2024-09-11T03:43:54","modified_gmt":"2024-09-11T03:43:54","slug":"devising-the-perfect-index-for-your-use-case-mysql-edition","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/devising-the-perfect-index-for-your-use-case-mysql-edition\/","title":{"rendered":"Devising the Perfect Index for Your Use Case \u2013 MySQL Edition"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>If you\u2019ve been following SimpleTalk for a while, you will be aware that I\u2019ve recently blogged about MySQL indexes. I\u2019ve already told you about <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/the-nuances-of-mysql-indexes\/\">the nuances of indexes in MySQL<\/a>, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/mysql-index-overviews-b-tree-indexes\/\">vanilla B-Tree indexes<\/a>, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/mysql-index-overviews-composite-b-tree-indexes\/\">composite B-Tree indexes<\/a>, and other kinds of indexes too.<\/p>\n\n\n\n<p>This blog will walk you through how to choose the perfect index for your specific use case. It will also advise you on the things you should consider to devise the perfect index design in MySQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">About Indexes in MySQL<\/h2>\n\n\n\n<p>One thing you should take away from those blogs is that there are two general types of indexes in MySQL that are often split into multiple different sub-types. We have B-tree indexes, and R-tree, or spatial, indexes.<\/p>\n\n\n\n<p>Most indexes will be related to the B-tree index type, and those that aren\u2019t will be considered R-tree indexes. Covering, composite, clustered, descending, unique, hash, full-text, and primary key indexes will be B-tree indexes, and spatial indexes will be R-tree indexes.<\/p>\n\n\n\n<p>A B-tree index is a balanced tree index. A balanced tree index is a data structure that sorts data and facilitates searching for data that\u2019s stored in a sorted order. It thus enables your database to find rows quicker.<\/p>\n\n\n\n<p>An R-tree index is an index that\u2019s used to find data falling within a general range, and then perform operations on that data. R-tree indexes are used to facilitate spatial searches \u2013 that is, searches through geographic data sets.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Indexing for Your Use Case<\/h2>\n\n\n\n<p>If you consider using indexes, you\u2019re most likely considering them to facilitate an end goal for your specific use case. That end goal is most likely related to one or more of the following points:<\/p>\n\n\n<div class=\"block-core-list\">\n<ol class=\"wp-block-list\">\n<li>You have quite a lot of data in your tables (think tens of millions of rows or more.)<\/li>\n\n\n\n<li>Your application necessitates search operations through bigger data sets.<\/li>\n\n\n\n<li>Your use case necessitates the removal of duplicate rows where necessary.<\/li>\n<\/ol>\n<\/div>\n\n\n<p>Indexes help these use cases because they can eliminate rows from consideration when a WHERE clause is in use.<\/p>\n\n\n\n<p>Most of your use cases will necessitate vanilla B-tree indexes unless your use case deals with geographical data. B-tree indexes can be applied when creating a table. To do that, add an INDEX clause once you define all of the necessary columns:<\/p>\n\n\n\n<p> <code>CREATE TABLE `demo_table` (<\/code><br><code>`col` VARCHAR(115) NOT NULL,<\/code><br><code>`col2` INT(5) NOT NULL,<\/code><br><code><strong>INDEX `idx_name`(`col`)<\/strong><\/code><br><code>); <\/code> <\/p>\n\n\n\n<p>Or when modifying data using the <code>CREATE INDEX<\/code> or <code>ALTER<\/code> clauses:<\/p>\n\n\n\n<p><code>CREATE INDEX `btree_idx` ON `demo_table`(`column`);<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ALTER TABLE `demo_table` ADD INDEX `btree_idx`(`column`);<\/code><\/pre>\n\n\n\n<p>Adding an index is easy, but choosing the specific index and designing it as necessary is a little harder.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Index to Choose for Your Use Case? Tips &amp; Tricks<\/h2>\n\n\n\n<p>To choose an index for your use case, consider the following:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Choose a <strong>vanilla B-tree index<\/strong>* <em>if you need to use an index to eliminate rows from consideration.<\/em> <em>It may help you when your use case doesn\u2019t necessitate any other kind of index type<\/em> (see index types below.)<\/li>\n\n\n\n<li>Choose a <strong>covering B-tree index<\/strong> <em>if your use case enables and\/or necessitates you to read data from the index<\/em> instead of reading it from the disk.<\/li>\n\n\n\n<li>Choose a <strong>multicolumn or composite index<\/strong> <em>if your <\/em><em><code>WHERE<\/code><\/em><em> clause involves multiple columns, your query includes <\/em><em><code>OR<\/code><\/em><em> clauses, or you want to make the query optimizer able to directly access the table if the column is not in the index.<\/em><\/li>\n\n\n\n<li>Choose a <strong>clustered index<\/strong> when your table must contain id columns. If you don\u2019t choose one, MySQL will contain a clustered index in the form of a primary key, anyway \u2013 refer to my blog about primary keys to learn more.<\/li>\n\n\n\n<li>Choose a <strong>descending index<\/strong> <em>when your use case necessitates all rows to be stored in a descending manner<\/em> (think using an <code>ORDER BY<\/code> clause to sort the results of a query in descending order, etc.)<\/li>\n\n\n\n<li>Use a <strong>unique index<\/strong> <em>when you need to get rid of duplicate rows inside of a table.<\/em><\/li>\n\n\n\n<li>Use a <strong>hash index<\/strong> <em>when your use case necessitates blazing fast searches using the MEMORY storage engine.<\/em><\/li>\n\n\n\n<li><em>Use a <strong>full-text index<\/strong> when your use case necessitates searches using \u201cfuzzy matching.\u201d<\/em> That may include wildcards, or searches in Boolean or query expansion modes. Full-text indexes allow you to include Boolean or other kind of sophisticated logic in your search queries. Their search modes are worth exploring too \u2013 for more information, refer to my blog post on full-text indexes.**<\/li>\n\n\n\n<li><em>Use a <strong>spatial index<\/strong> when your use case necessitates searching through geographic data<\/em>. More information <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/creating-spatial-indexes.html\">here<\/a>.<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">Rules Involving Indexes<\/h3>\n\n\n\n<p>Rules involving indexes are simple and they\u2019re not rocket science, however, one must be aware of the fact that each type of indexing comes with its unique propositions and problems. Most of those problems are <a href=\"https:\/\/www.red-gate.com\/simple-talk\/author\/lukas-vileikis\/\">already covered in my series on indexes in MySQL<\/a>, so I won\u2019t get into them here, so if you\u2019re curious, give these blogs a read!<\/p>\n\n\n\n<p><em>*A \u201cvanilla\u201d B-tree index is a B-tree index that is not a covering, composite, clustered, descending, unique, hash, full-text, or primary key index.<\/em><\/p>\n\n\n\n<p><em>**Wildcards are not exclusive to full-text searches and they can also be used when no indexes are in use or when other types of indexes are being used<\/em>. <em>Keep in mind that you cannot use them using the \u201c*\u201d symbol \u2013 we have to choose the percentage sign (\u201c%\u201d) instead.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to Devise the Perfect Index Design? Examples, Tips &amp; Tricks<\/h2>\n\n\n\n<p>Once you\u2019ve chosen the type of index you are going to employ to help your use case, it\u2019s time to devise the perfect index design.<\/p>\n\n\n\n<p>The way your \u201cperfect\u201d index design will look like will depend on a couple of factors, the main ones being:<\/p>\n\n\n<div class=\"block-core-list\">\n<ol class=\"wp-block-list\">\n<li><strong>The type of the index you chose<\/strong> \u2013 the type of index is directly related to your use case.<\/li>\n\n\n\n<li><strong>Your use case and the types of queries you run<\/strong> \u2013 in this case, your use case has a lot to do with the structure of your SELECT queries.<\/li>\n<\/ol>\n<\/div>\n\n\n<p>These two things are closely linked \u2013 choose the necessary index based on your query structure, and your query structure will be dictated by your use case.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Examples<\/h3>\n\n\n\n<p>Here are a couple of examples:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>ID<\/strong><\/td><td><strong>Query or Use Case<\/strong><\/td><td><strong>Index to Choose<\/strong><\/td><td><strong>Definition of the Index<\/strong><\/td><\/tr><tr><td>1<\/td><td><code>SELECT * FROM `demo` WHERE `col` = \u2018Value\u2019;<\/code><\/td><td>Vanilla B-tree index<\/td><td><code>CREATE INDEX `idx` ON `demo`(`col`);<\/code><\/td><\/tr><tr><td>2<\/td><td><code>SELECT * FROM `demo` WHERE `col` = \u2018Value\u2019 AND `c2` = \u2018Value 2\u2019;<\/code><\/td><td>Vanilla B-tree index (covering index)<\/td><td><code>CREATE INDEX `idx` ON `demo`(`col`,`c2`);<\/code><br>Alternatively, index #1.<\/td><\/tr><tr><td>3<\/td><td><code>SELECT * FROM `demo` WHERE MATCH(col) AGAINST(\u201cValue\u201d);<\/code><\/td><td>Full-text index<\/td><td><code>CREATE FULLTEXT INDEX `ftx` ON `demo`(`col`);<\/code><\/td><\/tr><tr><td>4<\/td><td><code>SELECT data FROM `demo` WHERE id = 1;<\/code><\/td><td>Clustered index<\/td><td><code>ALTER TABLE `demo` ADD PRIMARY KEY(`id`);<\/code><\/td><\/tr><tr><td>5<\/td><td>A lot of rows, adding a B-tree doesn\u2019t make sense, but data has to be indexed for <em>some<\/em> efficiency.<\/td><td>Partial index<\/td><td><code>CREATE INDEX `partial_idx` ON `demo`(`col`(10));<\/code><\/td><\/tr><tr><td>6<\/td><td><code>SELECT id,username FROM `demo` WHERE regdate LIKE \u20182016%\u2019<code> <strong>ORDER BY id DESC<\/strong>;<\/code><\/code><\/td><td>Descending index<\/td><td><code>CREATE INDEX `desc_idx` ON `demo`(`regdate`, `id` DESC); or CREATE INDEX `desc_idx` ON `demo`(`regdate` DESC);<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>For many \u201cvanilla\u201d use cases you may choose a vanilla B-tree index as shown in some of the examples below. Some use cases may necessitate you using a covering index (<em>consider a covering index when you search through a lot of data<\/em>.)<\/p>\n\n\n\n<p>Some use cases may necessitate a partial index to benefit from a B-tree index and save disk space at the same time. For a partial index to be effective, define the index on \u201cactive\u201d (i.e. used by the user) amount of characters in the column. To choose a proper character count for the partial index, consider your use case and define the partial index on the average number of characters that are searched through. For example, if your use case involves searching for email addresses, defining a partial index on the first 20 characters should help.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>Choosing a proper index and designing it properly is vital for your use case. <a href=\"https:\/\/www.red-gate.com\/simple-talk\/author\/lukas-vileikis\/\">My indexing series here on Simple-Talk<\/a> should give you a good enough insight into the index types available to choose from in MySQL, while this blog should give you enough examples to make adequate choices quickly.<\/p>\n\n\n\n<p>I hope you\u2019ve enjoyed this blog and that you will stick around the Redgate Simple Talk blog for a while. <a href=\"https:\/\/youtube.com\/@DatabaseDive\">Follow the Database Dive channel on YouTube<\/a> for more database news in a video format, and until next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog will walk you through how to choose the perfect index for your specific use case. It will also advise you on the things you should consider to devise the perfect index design in MySQL.&hellip;<\/p>\n","protected":false},"author":339547,"featured_media":103901,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2,143523,145792],"tags":[159172,5923,159178,159179,159177,159174,159175,159181,5854,159170,159180,159182,159173,159171,159176],"coauthors":[146040],"class_list":["post-103897","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blogs","category-databases","category-mysql","tag-b-tree-indexes","tag-clustered-index","tag-composite-index","tag-covering-index","tag-descending-index","tag-fulltext-indexes","tag-hash-index","tag-mariadb-server","tag-mysql","tag-mysql-database","tag-mysql-server","tag-percona-server","tag-spatial-indexes","tag-sql-index","tag-unique-index"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103897","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/339547"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=103897"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103897\/revisions"}],"predecessor-version":[{"id":103902,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103897\/revisions\/103902"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/103901"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=103897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=103897"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=103897"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=103897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}