Mysql
 sql >> Base de données >  >> RDS >> Mysql

Performances MySQL :plusieurs tables contre index sur une seule table et partitions

Créer 20 000 tables est une mauvaise idée. Vous aurez besoin de 40 000 tables d'ici peu, et plus encore.

J'ai appelé ce syndrome Metadata Tribbles dans mon livre SQL Antipatterns . Vous voyez cela se produire chaque fois que vous envisagez de créer un "tableau par X" ou une "colonne par X".

Cela pose de réels problèmes de performances lorsque vous avez des dizaines de milliers de tables. Chaque table nécessite que MySQL maintienne des structures de données internes, des descripteurs de fichiers, un dictionnaire de données, etc.

Il y a aussi des conséquences opérationnelles pratiques. Voulez-vous vraiment créer un système qui vous oblige à créer une nouvelle table chaque fois qu'un nouvel utilisateur s'inscrit ?

Au lieu de cela, je vous recommande d'utiliser Partitionnement MySQL .

Voici un exemple de partitionnement de la table :

CREATE TABLE statistics (
  id INT AUTO_INCREMENT NOT NULL,
  user_id INT NOT NULL,
  PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;

Cela vous donne l'avantage de définir une table logique, tout en divisant la table en plusieurs tables physiques pour un accès plus rapide lorsque vous recherchez une valeur spécifique de la clé de partition.

Par exemple, lorsque vous exécutez une requête comme votre exemple, MySQL accède uniquement à la partition correcte contenant le user_id spécifique :

mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: statistics
   partitions: p1    <--- this shows it touches only one partition 
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 2
        Extra: Using where; Using index

La méthode de partitionnement HASH signifie que les lignes sont placées dans une partition par un module de la clé de partition entière. Cela signifie que de nombreux user_id sont mappés sur la même partition, mais chaque partition n'aurait que 1/Nième de lignes en moyenne (où N est le nombre de partitions). Et vous définissez la table avec un nombre constant de partitions, vous n'avez donc pas à l'étendre à chaque fois que vous obtenez un nouvel utilisateur.

Vous pouvez choisir n'importe quel nombre de partitions jusqu'à 1024 (ou 8192 dans MySQL 5.6), mais certaines personnes ont signalé des problèmes de performances lorsqu'elles atteignent ce niveau.

Il est recommandé d'utiliser un nombre premier de partitions. Dans le cas où vos valeurs user_id suivent un modèle (comme n'utiliser que des nombres pairs), l'utilisation d'un nombre premier de partitions permet de répartir les données plus uniformément.

Répondez à vos questions en commentaire :

Pour le partitionnement HASH, si vous utilisez 101 partitions comme je le montre dans l'exemple ci-dessus, une partition donnée contient environ 1 % de vos lignes en moyenne. Vous avez dit que votre table de statistiques contient 30 millions de lignes, donc si vous utilisez ce partitionnement, vous n'auriez que 300 000 lignes par partition. C'est beaucoup plus facile à lire pour MySQL. Vous pouvez (et devriez) également utiliser des index - chaque partition aura son propre index, et il ne sera que de 1 % de la taille de l'index sur l'ensemble de la table non partitionnée.

Donc, la réponse à la question de savoir comment déterminer un nombre raisonnable de partitions est :quelle est la taille de votre table entière et quelle taille voulez-vous que les partitions aient en moyenne ?

Le nombre de partitions n'a pas nécessairement besoin d'augmenter si vous utilisez le partitionnement HASH. Finalement, vous pouvez avoir 30 milliards de lignes au total, mais j'ai constaté que lorsque votre volume de données augmente de plusieurs ordres de grandeur, cela nécessite de toute façon une nouvelle architecture. Si vos données deviennent si volumineuses, vous avez probablement besoin d'un sharding sur plusieurs serveurs ainsi que le partitionnement en plusieurs tables.

Cela dit, vous pouvez repartitionner une table avec ALTER TABLE :

ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;

Cela doit restructurer la table (comme la plupart des changements ALTER TABLE), alors attendez-vous à ce que cela prenne un certain temps.

Vous voudrez peut-être surveiller la taille des données et des index dans les partitions :

SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;

Comme avec n'importe quelle table, vous voulez que la taille totale des index actifs tienne dans votre pool de mémoire tampon, car si MySQL doit échanger des parties d'index dans et hors du pool de mémoire tampon pendant les requêtes SELECT, les performances en souffrent.

Si vous utilisez le partitionnement RANGE ou LIST, l'ajout, la suppression, la fusion et le fractionnement de partitions sont beaucoup plus courants. Voir http://dev.mysql. com/doc/refman/5.6/en/partitioning-management-range-list.html

Je vous encourage à lire la section du manuel sur le partitionnement , et consultez également cette présentation :Boost Performance Avec les partitions MySQL 5.1 .