Reputation: 18318
Below is my table and some queries I run that take a lot of time (10-40 seconds). What indexes should I add to make performance better without making the table's too big. Also I have been told that if I use 'abc%' for my like queries I can use an index. Is this true?
phppos_items
+-----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+----------------+
| name | varchar(255) | NO | | NULL | |
| category | varchar(255) | NO | | NULL | |
| supplier_id | int(11) | YES | MUL | NULL | |
| item_number | varchar(255) | YES | UNI | NULL | |
| description | varchar(255) | NO | | NULL | |
| cost_price | double(15,2) | NO | | NULL | |
| unit_price | double(15,2) | NO | | NULL | |
| quantity | double(15,2) | NO | | 0.00 | |
| reorder_level | double(15,2) | NO | | 0.00 | |
| location | varchar(255) | NO | | NULL | |
| item_id | int(10) | NO | PRI | NULL | auto_increment |
| allow_alt_description | tinyint(1) | NO | | NULL | |
| is_serialized | tinyint(1) | NO | | NULL | |
| deleted | int(1) | NO | | 0 | |
+-----------------------+--------------+------+-----+---------+----------------+
#checking if item exists
SELECT * FROM (`phppos_items`) WHERE `item_id` = 1
#Get all offset + limit, can take 20+ seconds, take longer as offset gets bigger
SELECT * FROM (`phppos_items`) WHERE `deleted` = 0 ORDER BY `name` asc LIMIT 16, 16
#Count all non deleted, haven't tested yet bug I would imagine it would take awhile as deleted is not indexed
SELECT * FROM (`phppos_items`) WHERE `deleted` = 0
#Filtering, haven't tested yet, but I would guess it would take a while as there are no indexes on any of these fields
SELECT * FROM (`phppos_items`) WHERE `quantity` <= reorder_level AND `is_serialized` = 1 AND `description` = '' AND `deleted` = 0 ORDER BY `name` asc
#Get info about a particular item. This is pretty fast
SELECT * FROM (`phppos_items`) WHERE `item_id` = 1
#Get info about an item based on item_number, this seems pretty fast
SELECT * FROM (`phppos_items`) WHERE `item_number` = '1234'
#Search queries, very slow
SELECT * FROM (`phppos_items`) WHERE `deleted` = 0 AND `name` LIKE '%abc%' ORDER BY `name` asc
SELECT DISTINCT `category` FROM (`phppos_items`) WHERE `deleted` = 0 AND `category` LIKE '%abc%' ORDER BY `category` asc
SELECT * FROM (`phppos_items`) WHERE `deleted` = 0 AND `item_number` LIKE '%abc%' ORDER BY `item_number` asc
SELECT * FROM (`phppos_items`) WHERE `deleted` = 0 AND `name` LIKE '%abc%' ORDER BY `name` asc
SELECT * FROM (`phppos_items`) WHERE `deleted` = 0 AND `item_number` LIKE '%abc%' ORDER BY `item_number` asc
SELECT * FROM (`phppos_items`) WHERE (name LIKE '%abc%' or item_number LIKE '%abc%' or category LIKE '%abc%') and deleted=0 ORDER BY `name` asc LIMIT 16
#Category search, pretty fast
SELECT DISTINCT `category` FROM (`phppos_items`) WHERE `deleted` = 0 AND `category` LIKE '%abc%' ORDER BY `category` asc
#Get Categories, pretty fast
SELECT DISTINCT `category` FROM (`phppos_items`) WHERE `deleted` = 0 ORDER BY `category` asc
Upvotes: 3
Views: 486
Reputation: 89102
Another good rule of thumb is never to use
select *
in a non-trivial query. Instead, list out the columns you need.
If you're only checking for existence of a row, you can use
select count(*)
Upvotes: 1
Reputation: 80031
Your search queries are not using any index at all and can't use an index with the current query.
If you do a like '%....%'
than it is impossible to use an index.
Your options here are:
like '...%'
As for your limit
/offset
problem.
Instead of using offset
, try using something like name > 'previous name'
. Although something like that will only work correctly if name
is unique. In general you never want to use a limit
/offset
beyond 1000 since the database will have to walk through all of those rows.
Upvotes: 4
Reputation: 6161
General rule of thumb is to look at the WHERE
clause and index the columns used there. Looking at what you have the first candidates would be adding indices to deleted
and item_number
. MySQL will put an index on the primary key for you. SHOW INDEX
will show you index information for a table.
What you said about not having wildcards at the beginning of the LIKE
parameter is true. Take a look at this question. The way an INDEX
is built for a string is by looking at the string from start to finish and inserting it in the index that way. It looks like from your queries you may need to look into FULLTEXT
indexes or possibly reworking the problem so you don't have to create FULLTEXT
indexes.
Upvotes: 3