I have a query on my MySQL database that is used to return products (on an e-commerce site) after the user performs a search in a free-form text box.
Until recently, user searches have been running fast. However, in the last few days, the searches are periodically very slow. This occurs for about 3 or 4 hours (spread randomly throughout the day) each day.
I had thought that there was a problem with my server. But now I have moved to another server, and the same thing still happens.
I suspect that the query I use is quite inefficient, and maybe this is the cause. But I don't understand why usually the query can run fast, and at other times be very slow. I would assume that an inefficient query would always be slow.
The query runs on two tables. If the search is for "blue jeans", then the query would look like this:
SELECT I.itemURL, I.itemTitle, I.itemPrice, I.itemReduced, I.itemFileName, I.itemBrand, I.itemStore, I.itemID, I.itemColour, I.itemSizes, I.itemBrandEn
FROM Item AS I, Search AS S
WHERE I.itemID = S.itemID
AND (S.searchStringTEXT LIKE '% blue %' OR S.searchStringTEXT LIKE 'blue %' OR S.searchStringTEXT LIKE '% blue')
AND (S.searchStringTEXT LIKE '% jeans %' OR S.searchStringTEXT LIKE 'jeans %' OR S.searchStringTEXT LIKE '% jeans')
Item is the table containing all products on the site. It has around 100,000 rows.
Search is a table containing product ids, and the tags associated to each product id. The tags are in the column "searchStringTEXT", and are separated by spaces. E.g., an entry in this column may be something like "jeans blue calvin klein small".
The search above will find all items that have both the tag "jeans" and "blue" attached.
In theory, Search should have the same number of rows as Item; but, due to a problem that I haven't fixed yet, it has about 500 fewer rows, so these items are effectively excluded from searches.
The create table details for both tables are as follows:
CREATE TABLE `Search` (
`itemID` int(11) NOT NULL,
`searchStringTEXT` varchar(255) DEFAULT NULL,
`searchStringVARCHAR` varchar(1000) DEFAULT NULL,
PRIMARY KEY (`itemID`),
KEY `indexSearch_837` (`itemID`) USING BTREE,
KEY `indexSearch_837_text` (`searchStringTEXT`)
) ENGINE=InnoDB DEFAULT CHARSET=latin5
and
CREATE TABLE `Item_8372` (
`itemID` int(11) NOT NULL AUTO_INCREMENT,
`itemURL` varchar(2000) DEFAULT NULL,
`itemTitle` varchar(500) DEFAULT NULL,
`itemFileName` varchar(200) DEFAULT NULL,
`itemPictureURL` varchar(2000) DEFAULT NULL,
`itemReduced` int(11) DEFAULT NULL,
`itemPrice` int(11) DEFAULT NULL,
`itemStore` varchar(500) DEFAULT NULL,
`itemBrand` varchar(500) CHARACTER SET latin1 DEFAULT NULL,
`itemShopCat` varchar(500) DEFAULT NULL,
`itemTimestamp` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`itemCat` varchar(200) DEFAULT NULL,
`itemSubCat` varchar(200) DEFAULT NULL,
`itemSubSubCat` varchar(200) DEFAULT NULL,
`itemSubSubSubCat` varchar(200) DEFAULT NULL,
`itemColour` varchar(200) DEFAULT NULL,
`itemSizes` varchar(200) DEFAULT NULL,
`itemBrandEn` varchar(500) DEFAULT NULL,
`itemReduction` float DEFAULT NULL,
`ItemPopularity` int(6) DEFAULT NULL,
PRIMARY KEY (`itemID`),
KEY `indexItem_8372_ts` (`itemTimestamp`) USING BTREE,
KEY `indexItem_8372_pop` (`ItemPopularity`),
KEY `indexItem_8372_red` (`itemReduction`),
KEY `indexItem_8372_price` (`itemReduced`)
) ENGINE=InnoDB AUTO_INCREMENT=970846 DEFAULT CHARSET=latin5
In the title of the question I say "(when run on my website)", because I find that the query's speed is consistent when run locally. But maybe this is just because I haven't tested it as much locally.
I'm thinking of changing the Search table so it's a MyISAM table, and then I can use a full text search instead of "LIKE". But I'd still like to figure out why I am experiencing what I am experiencing with the current setup.
Any ideas/suggestions much appreciated, Andrew
Edit:
Here is the EXPLAIN result for the SELECT statement:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE I ALL PRIMARY NULL NULL NULL 81558
1 SIMPLE S eq_ref PRIMARY,indexSearch_837,indexSearch_837_text PRIMARY 4 I.itemID 1 Using where