2011-05-30 3 views
3

Voici ma table et quelques requêtes que je cours qui prennent beaucoup de temps (10-40 secondes). Quels index devrais-je ajouter pour améliorer les performances sans que la table soit trop grande? Aussi, on m'a dit que si j'utilise 'abc%' pour mes requêtes, je peux utiliser un index. Est-ce vrai?Amélioration des performances avec beaucoup de lignes (1 000 000 + enregistrements)

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 

Répondre

3

règle générale est de regarder la clause WHERE et indexer les colonnes qui y sont utilisés. En regardant ce que vous avez les premiers candidats serait d'ajouter des indices à deleted et item_number. MySQL mettra un index sur la clé primaire pour vous. SHOW INDEX affichera les informations d'index pour une table.

Ce que vous avez dit à propos de l'absence de caractères génériques au début du paramètre LIKE est vrai. Jetez un oeil à ce question. La façon dont un INDEX est construit pour une chaîne est en regardant la chaîne du début à la fin et en l'insérant dans l'index de cette façon. Il semble que de vos requêtes, vous devrez peut-être regarder dans les index FULLTEXT ou éventuellement retravailler le problème afin de ne pas avoir à créer d'index FULLTEXT.

4

Vos requêtes de recherche n'utilisent aucun index et ne peuvent pas utiliser d'index avec la requête en cours. Si vous faites like '%....%' il est impossible d'utiliser un index.

Vos options sont ici:

  1. Modifier votre requête à quelque chose comme ceci: like '...%'
  2. Utilisez une table MyISAM avec la recherche du texte intégral
  3. Utilisez un moteur de recherche de texte intégral séparé (Sphinx, Solr, etc. ..)

Quant à votre limit/offset problème.

Au lieu d'utiliser offset, essayez d'utiliser quelque chose comme name > 'previous name'. Bien que quelque chose comme ça ne fonctionnera correctement que si name est unique. En général, vous ne voulez jamais utiliser un limit/offset au-delà de 1000 car la base de données devra parcourir toutes ces lignes.

1

Une autre bonne règle est de ne jamais utiliser

select * 

dans une requête non trivial. Au lieu de cela, dressez la liste des colonnes dont vous avez besoin.

Si vous vérifiez que l'existence d'une ligne, vous pouvez utiliser

select count(*) 
Questions connexes