it-swarm-fr.com

Raisons de requêtes parfois lentes?

Nous exécutons MySQL 5.1 sur Windows Server 2008 R2.

Nous avons fait des diagnostics sur notre base de données de retard et avons trouvé des problèmes dérangeants artefacts que nous ne pouvons pas expliquer . Nous avons ajouté du code pour vous connecter lorsque nous avions des questions qui ont pris beaucoup de temps (> 2000ms). Les résultats étaient surprenants (et éventuellement une explication de nos blocages).

Parfois, des requêtes, qui prennent normalement très peu de temps (<10ms), prennent de 4 à 13 secondes. Pour être clairs, ce sont des requêtes qui fonctionnent constamment (plusieurs fois par seconde) et ne souffrent pas de ces pointes de temps de requête.

Nous avons traversé nos indices à la recherche de erreurs évidentes et nous n'avons pas beaucoup de chance.

Mise à jour

La table des gens:

| people | CREATE TABLE `people` (
`people_id` bigint(20) NOT NULL AUTO_INCREMENT,
`company_id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`temp_password` varchar(10) DEFAULT NULL,
`reset_password_hash` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`phone` varchar(32) DEFAULT NULL,
`mobile` varchar(32) DEFAULT NULL,
`iphone_device_id` varchar(160) DEFAULT NULL,
`iphone_device_time` datetime DEFAULT NULL,
`last_checkin` datetime DEFAULT NULL,
`location_lat` double DEFAULT NULL,
`location_long` double DEFAULT NULL,
`gps_strength` smallint(6) DEFAULT NULL,
`picture_blob_id` bigint(20) DEFAULT NULL,
`authority` int(11) NOT NULL DEFAULT '0',
`active` tinyint(1) NOT NULL DEFAULT '1',
`date_created` datetime NOT NULL,
`last_login` datetime NOT NULL,
`panic_mode` tinyint(1) NOT NULL DEFAULT '0',
`battery_level` double DEFAULT NULL,
`battery_state` varchar(32) DEFAULT NULL,
PRIMARY KEY (`people_id`),
KEY `email` (`email`),
KEY `company_id` (`company_id`),
KEY `iphone_device_id` (`iphone_device_id`),
KEY `picture_blob_id` (`picture_blob_id`),
CONSTRAINT `people_ibfk_1` FOREIGN KEY (`company_id`) REFERENCES `companies` (`company_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `people_ibfk_2` FOREIGN KEY (`picture_blob_id`) REFERENCES `blobs` (`blob_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4658 DEFAULT CHARSET=utf8 |

Index:

+--------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table  | Non_unique | Key_name         | Seq_in_index | Column_name      | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
| people |          0 | PRIMARY          |            1 | people_id        | A         |        3502 |     NULL | NULL   |      | BTREE      |         |
| people |          1 | email            |            1 | email            | A         |        3502 |     NULL | NULL   | YES  | BTREE      |         |
| people |          1 | company_id       |            1 | company_id       | A         |        3502 |     NULL | NULL   |      | BTREE      |         |
| people |          1 | iphone_device_id |            1 | iphone_device_id | A         |        3502 |     NULL | NULL   | YES  | BTREE      |         |
| people |          1 | picture_blob_id  |            1 | picture_blob_id  | A         |        3502 |     NULL | NULL   | YES  | BTREE      |         |
+--------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+

nous avons ~ 5000 lignes dans la table sur le serveur qui nous donnent des problèmes.

16
RedBlueThing

Les requêtes de mise à jour dans vos deux questions précédentes ( question1 , question2 ) frappent la table 'People' par clé primaire avec verrouillage de niveau de rangée. C'est ce que j'ai déclaré dans la question1 le 6 juin 2011 10:03

Toutes les transactions sont déplacées sur la clé primaire. Étant donné que le primaire est un indice en cluster dans Innodb, la clé primaire et la rangée elle-même sont ensemble. Ainsi, traverser une rangée et la clé primaire est une et la même chose. Par conséquent, tout verrouillage d'index sur la clé primaire est également un verrou de niveau de ligne.

Quelque chose d'autre n'a pas encore été envisagé d'attribuer la lenteur aux index: l'utilisation d'index non uniques dans InnoDB. Chaque recherche indexée en InnoDB à l'aide d'index non uniques a également le railid de chaque ligne attachée à la clé non unique. Le Rowid élimine essentiellement de l'indice en cluster . La mise à jour des index non uniques doit toujours interagir avec l'index en cluster, même si la table n'a pas de clé primaire.

Une autre chose à penser est le processus de gestion des nœuds BTREE dans un indice. Parfois, cela nécessite la scission de la page des nœuds. Toutes les entrées du nœud BTREE d'index non uniques contiennent des champs non uniques plus le Rowid au sein de l'indice en cluster. Pour atténuer correctement la scission de ces pages BTREE sans déranger l'intégrité des données, la ligne associée au Rowid doit faire l'expérience d'un verrouillage de niveau de ligne en interne.

Si la table 'People' a beaucoup d'index non uniques, préparez-vous à avoir un grand nombre de pages d'index dans l'espace de table ainsi que d'avoir de minuscules petites lignes de serrures se faufiler de temps en temps.

Il y a un autre facteur qui n'est pas aussi évident: la population clé

Parfois, lorsqu'un index est renseigné, les valeurs de clé de création des index pourraient devenir déséquilibrées au fil du temps et faire passer l'optimiseur de requête MySQL à passer des recherches touchées, aux analyses d'index et enfin aux analyses de la table complète. Que vous ne pouvez pas contrôler sauf si vous redessinez la table avec de nouveaux index pour compenser les clés OT de la méopitée. Veuillez fournir la structure de la table pour la table 'People', le compte de la table "Personnes" et la sortie de spectacle pour la table "personnes" .

Même si les requêtes n'utilisent que la clé primaire, la synthèse des touches des clés dans des index non uniques nécessite toujours un équilibrage de Bree et une scission de page pour se produire. Une telle gestion BTREE produira un ralentissement notable en raison des serrures de niveau de ligne intermittentes que vous n'avez pas l'intention de se produire.

Mise à jour 2011-06-14 22:19

Quères de la question 1

UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'Android:<id>-<id>',
iphone_device_time = '2011-06-06 05:35:09', last_checkin = '2011-06-06 05:24:42',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125

UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'Android:<id>-<id>-<id>-<id>',
iphone_device_time = '2011-06-06 05:24:42', last_checkin = '2011-06-06 05:35:07',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125

Image de la séquence dans les événements

  1. Trouver la ligne par clé primaire
  2. Verrouiller la ligne et l'index en cluster
  3. Créer des données MVCC pour toutes les colonnes étant la mise à jour
  4. Quatre colonnes sont indexées (e-mail, société_id, iphone_device_id, image_blob_id)
  5. Chaque index nécessite la gestion BTREE
  6. Dans le même espace de transaction, les étapes 1 à 5 tentent d'être répétées sur la même ligne, à la mise à jour des mêmes colonnes (e-mail identique dans les deux requêtes, Société_id la même dans les deux requêtes, image_blob_id identique dans les deux requêtes, iphone_device_id différent)

Quertise de la question 2

UPDATE people SET iphone_device_id=NULL
WHERE iphone_device_id='iphone:<device_id_blah>' AND people_id<>666;

UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com',
phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>',
iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47',
location_lat = <lat>, location_long = <lng>, gps_strength = 66,
picture_blob_id = 1661,
authority = 1, active = 1, date_created = '2011-03-20 19:18:34',
last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55,
battery_state = 'unplugged' WHERE people_id = 666;

Ces deux requêtes sont encore plus déroutantes car la première requête met à jour tout sauf les personnes_ID 666. Des centaines de lignes sont douloureusement verrouillées avec juste la première requête. La deuxième requête met à jour les personnes_ID 666 exécutant la 5 séquence d'événements. La première requête exécute ces mêmes 5 séquences d'événements sur chaque rangée impliquée, à l'exception des personnes_ID 666, mais l'index de iPhone_Device_ID est sur un cours intéressant avec deux requêtes différentes. Quelqu'un doit bien verrouiller les pages BTREE sur une base de premier arrivée - premier servi.

Face à ces deux paires de requêtes sur un parcours de collision pour verrouiller éventuellement les mêmes pages BTTREE dans un seul indice peut être une expérience de déchirure d'intestin pour innoDB ou tout SGBD conformément à l'acide. Ainsi, un ralentissement d'index est le destin de ces paires de requêtes, à moins que vous ne puissiez garantir que les requêtes fonctionnent avec Autocommit = 1 ou en permettant des lectures sales (bien que des collisions telles que celles-ci rendent la lecture et la lecture non engagées un cauchemar pour MVCC).

Mise à jour 2011-06-15 10:29

@Redblehinghoing: Dans les requêtes de la question 2, la première requête est une requête de gamme, de sorte que de nombreux serrures de rangée sont atteints. Remarquez également que les deux requêtes tentent de verrouiller le même ID d'espace n ° 4611 N BITS 152 est en cours de verrouillage dans la clé primaire, aka index en cluster.

Afin de vous assurer que votre application est, à tout le moins, en fonction de la série d'événements que vous attendez, il existe deux options différentes que vous pourriez essayer:

Option 1) Convertissez cette table en Myisam (au moins sur un serveur de développement). Chaque mise à jour, insertion et Supprimez-vous imposer une serrure de table complète sur une base de premier lieu, premier servi.

Option 2) Essayez d'utiliser le [~ # ~] sérialisable [~ # ~ ~] niveau d'isolement. Cela verrouille toutes les lignes prévues en mode partagé.

La séquence des événements que vous attendez de casserez ou réussissez à utiliser ces deux options alternatives. Si ces deux options échouent, vous devrez alors examiner votre application et donner la priorité à l'ordre d'exécution de vos questions. Une fois que vous avez établi cette priorité, vous pouvez simplement annuler ces options (pour l'option 1, revenir à innoDB, pour l'option 2, revenir au niveau d'isolement par défaut [STOP à l'aide de SERIALISABLE]).

14
RolandoMySQLDBA

Montrer des variables comme 'innodb%'; - En particulier, si les données et les index ne sont tout simplement pas atteintes de la taille du pool tampon, vous pouvez frapper le disque beaucoup plus fort qu'auparavant. E/S est le grand tueur de performance.

La plupart de vos champs sont deux fois plus gros que nécessaire. Bigint (8 octets) est trop exclu pour la plupart des identifiants. 5000 rangées ne nécessitent qu'un peu non signé (limite de 65k, seulement 2 octets). Ou utiliser moyennant une marge de sécurité.

Le double vous donne 16 chiffres significatifs à un coût de 8 octets. Battery_level a-t-il plus de 2 chiffres significatifs de précision? Le flotteur prend 4 octets.

Mon point ici est que "plus petit -> plus cacheable -> plus rapide".

S'il vous plaît montrez-nous les requêtes lentes; au moins certains de ceux qui sont soudainement devenus plus lents. Nous ne pouvons que faire des suppositions sans eux. Allumez le ralentisseur et définissez long_query_time = 1; Celles-ci aideront à trouver les requêtes les plus lentes.

Comprenez-vous l'avantage des indices "composés"?

3
Rick James