Улучшение производительности с большим количеством строк (более 1 000 000 записей) - PullRequest
3 голосов
/ 30 мая 2011

Ниже моя таблица и некоторые запросы, которые я выполняю, которые занимают много времени (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 ]

4 голосов
/ 30 мая 2011

Ваши поисковые запросы вообще не используют никакого индекса и не могут использовать индекс с текущим запросом.

Если вы делаете like '%....%', то невозможно использовать индекс.

Ваши варианты здесь:

  1. Измените ваш запрос на что-то вроде этого: like '...%'
  2. Использование таблицы MyISAM с полнотекстовым поиском
  3. Использовать отдельную систему полнотекстового поиска (Sphinx, Solr и т. Д ...)

Что касается вашей limit / offset проблемы.

Вместо использования offset, попробуйте использовать что-то вроде name > 'previous name'. Хотя что-то подобное будет работать правильно, только если name уникально. В общем случае вы никогда не захотите использовать limit / offset за 1000, поскольку базе данных придется пройти по всем этим строкам.

3 голосов
/ 30 мая 2011

Общее правило: посмотрите на предложение WHERE и проиндексируйте используемые там столбцы. Глядя на то, что у вас есть первые кандидаты, вы добавите индексы к deleted и item_number. MySQL поместит индекс на первичный ключ для вас. SHOW INDEX покажет вам индексную информацию для таблицы.

То, что вы сказали об отсутствии подстановочных знаков в начале параметра LIKE, соответствует действительности. Взгляните на этот вопрос . Для строки INDEX создается просмотр строки от начала до конца и вставка ее в индекс таким образом. Судя по вашим запросам, вам может понадобиться просмотреть индексы FULLTEXT или, возможно, переработать проблему, чтобы вам не пришлось создавать индексы FULLTEXT.

1 голос
/ 30 мая 2011

Другое хорошее эмпирическое правило - никогда не использовать

select * 

в нетривиальном запросе.Вместо этого перечислите нужные вам столбцы.

Если вы проверяете наличие строки, вы можете использовать

select count(*)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...