通过大量行(1,000,000 +记录)提高性能

时间:2011-05-30 01:35:58

标签: mysql indexing

下面是我的表格和我运行的一些查询需要花费很多时间(10-40秒)。我应该添加哪些索引,以便在不使表太大的情况下提高性能。另外我被告知,如果我使用'abc%'作为我喜欢的查询,我可以使用索引。这是真的吗?

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

3 个答案:

答案 0 :(得分:4)

您的搜索查询根本没有使用任何索引,也无法使用当前查询的索引。

如果您执行like '%....%',则无法使用索引。

您的选择是:

  1. 将您的查询更改为以下内容:like '...%'
  2. 使用带有全文搜索的MyISAM表
  3. 使用单独的全文搜索引擎(Sphinx,Solr等...)

  4. 至于您的limit / offset问题。

    请尝试使用offset之类的内容,而不要使用name > 'previous name'。虽然name是唯一的,但类似的东西才能正常工作。通常,您永远不想使用超过1000的limit / offset,因为数据库必须遍历所有这些行。

答案 1 :(得分:3)

一般的经验法则是查看WHERE子句并索引其中使用的列。查看您拥有的第一批候选人将为deleteditem_number添加索引。 MySQL将为您提供主键索引。 SHOW INDEX将显示表的索引信息。

关于在LIKE参数的开头没有通配符的说法是正确的。看一下这个question。为字符串构建INDEX的方法是从开始到结束查看字符串并将其插入到索引中。从您的查询看起来,您可能需要查看FULLTEXT索引或可能重新处理问题,因此您不必创建FULLTEXT索引。

答案 2 :(得分:1)

另一个好的经验法则是永远不要使用

select * 

在一个非平凡的查询中。而是列出您需要的列。

如果您只检查是否存在行,则可以使用

select count(*)