Manual:Database access/fr

Cet article donne un aperçu de l'accès aux bases de données et des problèmes généraux liés à ces bases dans MediaWiki.

Lorsque vous codez dans MediaWiki, vous accèdez normalement à la base de données uniquement par les fonctions dédiées de MediaWiki.

Schéma des bases de données
Pour les informations concernant le schéma de la base de données MediaWiki, telles que la description des tables et leur contenu, voir. Historiquement dans MediaWiki, ceci était aussi documenté dans, néanmoins à partir de MediaWiki 1.35, cela sera déplacé progressivement dans   comme partie de l'initiative du schéma abstrait (Abstract Schema initiative). Cela signifie que  est transformé en   par un, ce qui le rend plus facile à générer les fichiers du schéma pour prendre en charge les différents moteurs de base de données.

Utiliser sql.php
MediaWiki fournit un script de maintenance pour accéder à la base de données. Exécutez depuis le répertoire maintenance :

Vous pouvez ensuite émettre des requêtes vers la base de données. Vous pouvez aussi fournir un nom de fichier que MediaWiki exécutera, en substituant les variables spéciales de MediaWiki selon le cas. Pour plus d'informations, voir.

Cela fonctionne avec tout serveur de base de données. Néanmoins l'invite n'a pas toutes les fonctionnalités du client de commandes en mode ligne fourni avec votre base de données.

Utiliser le client de commandes en ligne mysql
Votre nom d'utilisateur et mot de passe MySQL se trouvent dans le fichier LocalSettings.php, par exemple :

Avec SSH, connectez-vous ainsi :

en remplaçant  et   par l'information contenue dans le fichier. On vous demandera ensuite votre mot de passe  avant d'afficher l'invite.

Niveau d'abstraction de la base de données
MediaWiki fournit un niveau d'abstraction de la base de données. Sauf si vous travaillez sur le niveau d'abstraction, vous n'avez en aucun cas à appeler directement les fonctions PHP de la base de données (telles que  ou  .)

Le niveau d'abstraction est accessible via la classe. Une instance de cette classe peut être obtenue en appelant  (de préférence) ou   sur un   injecté. La fonction  est en fin de vie et ne doit pas être utilisée dans le nouveau code. Une autre possibilité est typiquement d'être appelé avec un seul paramètre, qui est la constante  (pour les demandes de lecture) ou   (pour les demandes d'écriture et les lectures qui ont besoin absolument de l'information la plus récente). La distinction entre master et réplicat est importante dans un environnement multi-bases, tel que Wikimedia. Voir la section des fonctions conteneur ci-après pour connaître les possibilités d'utilisation de l'objet  qui est renvoyé.

Les conteneurs de résultat des requêtes select sont des tableaux dont les clés sont des entiers qui commencent à 1. Pour faire une demande de lecture, le code suivant suffit habituellement :

""

Pour une requête d'écriture, utiliser un code similaire à :

""

Nous utilisons la convention pour la lecture et  pour l'écriture afin de vous aider à suivre le cas où l'objet base de données est un réplicat (lecture seule) ou un master (lecture/écriture). Si vous écrivez dans un replicat, le monde risque d'exploser. Ou pour être plus précis, la requête suivante d'écriture qui a réussi sur le master peut échouer lors de la duplication sur le réplicat parce que la clé est déja définie. La duplication sur le réplicat va s'arrêter et la réparation de la base de données peut prendre des heures avant que celle-ci ne remonte en ligne. En initialisant read_only dans my.cnf pour le réplicat, vous éviterez ce scenario, mais étant donné les conséquences désastreuses, nous préférons avoir autant de contrôles que possible.

SelectQueryBuilder
The class is the preferred way to write read queries, replacing the   family of  methods (see below). Usually, it is used in a "fluent" style, where you directly call methods on the query builder without assigning it to a variable, for example:

This example corresponds to the query:

JOINs are also possible; for example:

This example corresponds to the query:

You can access individual rows of the result using a foreach loop. Once you have a row object, you can use the operator to access a specific field. A full example might be:

There are also convenience functions to fetch a single row, a single field from several rows, or a single fields from a single row:

In this example, will be a row object like in the  example above,  will be an array of page ID values, and  will be a single page ID value.

Fonctions conteneur
Nous fournissons une fonction query pour le SQL brut, mais les fonctions conteneur telles que select et insert sont habituellement plus pratiques. Elles peuvent prendre en compte des éléments tels que les préfixes de tables et l'échappement des caractères dans certaines situations. Si vous devez réaliser votre propre SQL, veuillez lire la documentation concernant tableName et addQuotes. Les deux vous seront nécessaires. Gardez à l'esprit que le fait de ne pas utiliser addQuotes correctement peut entraîner des failles importantes dans la sécurité de votre wiki.

Une autre raison importante pour utiliser les méthodes de haut niveau plutôt que de construire vos propres requêtes est pour vous assurer que votre code s'exécutera correctement indépendamment du type de base de données. Actuellement MySQL et MariaDB sont les mieux prises en charge. SQLite bénéficie également d'un bon support mais il est beaucoup plus lent que MySQL et MariaDB. Le support de PostgreSQL existe également mais il n'est pas aussi stable que pour MySQL.

Dans la suite, nous listons les fonctions conteneur disponibles. Pour une description détaillée des paramètres des fonctions conteneur, voir les documents concernant la classe. Voir en particulier  pour l'explication des paramètres suivants, utilisés dans les autres fonctions conteneur : ,  ,  ,  ,  , et.

Fonction conteneur : select
La fonction select fournit l'interface MediaWiki pour une instruction SELECT. Les composants de l'instruction SELECT sont codés comme les paramètres de la fonction select. Exemple :

Cet exemple correspond à la requête :

Les JOINs sont également possibles; par exemple :

Cet exemple correspond à la requête :

fournit un exemple sur la manière d'utiliser les alias de tables dans les requêtes.

Les arguments sont soit des valeurs uniques (comme 'category' ou 'cat_pages > 0'), soit des tableaux si plus d'une valeur est fournie pour une position d'argument (tel que ['cat_pages > 0', $myNextCond]). Si vous passez des chaînes de caractères dans le troisième ou le cinquième argument, vous devez protéger manuellement vos valeurs avec  au fur et à mesure que vous construisez la chaîne car le conteneur ne le fait pas pour vous. Les valeurs des noms de tables (premier argument) ou celles des noms de champs (second argument) ne doivent pas être contrôlées par l'utilisateur. La construction du tableau pour $conds est un peu limitée; elle ne peut traiter que l'égalité et les relations  (c'est à dire où WHERE key = 'value').

Vous pouvez accéder séparément à chaque ligne du résultat en utilisant une boucle foreach. Une fois l'objet ligne obtenu, vous pouvez utiliser l'opérateur  pour accéder à un champ particulier. Un exemple complet serait :

Ce qui ajoutera une liste alphabétique des catégories (avec respectivement leur nombre d'entrées) à la variable $output. Si la sortie se fait en HTML, assurez-vous d'échapper les valeurs de la base de données avec

Fonctions pratiques
Pour être compatible avec PostgreSQL, les IDs d'insertion sont obtenus en utilisant nextSequenceValue et insertId. Le paramètre pour nextSequenceValue peut être obtenu par l'option  dans   et suit toujours le format x_y_seq, avec pour x le nom de la table (c'est à dire celui de la page) et pour y la clé primaire (c'est à dire le page_id), pour donner page_page_id_seq. Par exemple :

Pour d'autres fonctions utiles comme affectedRows, numRows, etc., voir Manual:Database.php.

Optimisation de la requête de base
Les développeurs MediaWiki qui doivent écrire des requêtes dans une base de données doivent avoir certaines notions concernant les bases de données et être conscients des problèmes de performance qu'elles peuvent poser. Les correctifs contenant des fonctions particulièrement lentes ne seront pas acceptés. Les requêtes non indexées ne sont généralement pas les bienvenues dans MediaWiki, sauf dans les pages spéciales dérivées de QueryPage. Un piège général pour les nouveaux développeurs c'est de soumettre un code contenant des requêtes SQL qui examinent un trop grand nombre de lignes. Pensez que COUNT(*) vaut O(N); compter le nombre de lignes dans une table c'est comme compter des graines dans un seau.

Compatibilité arrière
Souvent et à cause des modifications dans la structure de la base de données, différents accès à la base de données sont nécessaires pour assurer la compatibilité arrière. Ceci peut être réalisé par exemple à l'aide des variables globales et.

Réplication
Les installations étendues de MediaWiki telles que Wikipedia, utilisent un vaste ensemble de serveurs MySQL répliqués qui dupliquent chacuns les écritures faites sur le serveur MySQL maître. Il est important de comprendre les problèmes liés à ce paramètre si vous souhaitez écrire du code pour Wikipedia.

C'est souvent le cas où le meilleur algorithme à utiliser pour une tâche donnée dépend du fait que la réplication est utilisée ou pas. En raison de notre centrisme Wikipédia sans vergogne, nous utilisons souvent la version de réplication sympatique, mais si vous le souhaitez, vous pouvez utiliser pour savoir si la réplication est utilisée.

Latence
La latence (c'est à dire le retard ou encore le décalage) apparaît principalement lorsqu'un grand nombre d'écritures est envoyé au master. Les écritures sur le master sont exécutées en parallèle mais sont faites en série quand elles sont dupliquées sur les réplicats. Le master enregistre la reqête dans le journal (binlog) quand la transacton est validée (commit). Les réplicats scrutent le binlog et démarrent l'exécution de la requête dès qu'elle apparaît. Ils peuvent répondre aux demandes de lecture en même temps qu'ils traitent une requête d'écriture mais ils ne lisent plus rien dans le binlog et ne traitent donc pas d'autres écritures. Cela signifie que si la demande d'écriture a besoin de temps pour s'exécuter, les réplicats vont attendre le master, le temps qu'il termine sa demande d'écriture.

La latence peut s'allonger quand la charge due aux lectures trop nombreuses augmente. Le partage de charge dans MediaWiki arrête d'envoyer les lectures au réplicat lorsque ce décalage dépasse 30 secondes. Si les seuils de charge sont mal positionnés, ou s'il y a trop de charge habituellement, cela peut faire qu'un réplicat soit toujours décalé d'environ 30 secondes.

Si tous les réplicats sont décalés de plus de 30 secondes (selon la valeur de ), MediaWiki arrête d'écrire dans la base de données. Toutes les modifications et autres opérations d'écriture sont refusées et une erreur est renvoyée à l'utilisateur. Ceci laisse aux réplicats une chance de se mettre à jour. Avant que nous ayons ce mécanisme, les réplicats étaient régulièrement à la traîne de quelques minutes, ce qui rendait difficile la relecture des modifications récentes.

De plus, MediaWiki essaie de respecter l'ordre chronologique des événements arrivant sur le wiki pour qu'ils soient vus dans l'ordre par l'utilisateur. Il est acceptable d'avoir quelques secondes de décalage, tant que l'utilisateur perçoit une image cohérente suite aux requêtes consécutives. Ceci est réalisé en indiquant l'emplacement du binlog du master dans la session, puis au début de chaque requête en attendant que le replicat s'accroche à cette position avant d'aller y lire. Si ce délai expire, les lectures sont autorisées mais la requête est considérée être en mode réplicat différé. Le mode réplicat différé peut être vérifié en appelant. La seule conséquence pratique actuellement est l'affichage d'un avertissement au bas de la page.

Les utilisateurs du shell peuvent voir le temps de réplication avec ; les autres peuvent utiliser l'API.

Les bases de données ont souvent aussi leur propre système de contrôle en place, voir par exemple pour MariaDB (Wikimedia) et sur Toolforge (VPS Wikimedia Cloud).

Pour éviter la latence
Pour éviter les délais excessifs, les requêtes demandant un grand nombre d'écritures doivent être découpées en paquets plus petits (en général une écriture par ligne). Les requêtes multilignes INSERT ... SELECT sont les pires situations et doivent toutes être évitées. Au lieu de cela, faites d'abord le select puis l'insert.

Même les petites écritures peuvent provoquer une attente si leur fréquence est trop grande et que la réplication n'a pas le temps de les satisfaire correctement. Cela arrive le plus souvent dans les scripts de maintenance. Pour empêcher cela vous devez appeler régulièrement après quelques centaines d'écritures. La plupart des scripts rendent le nombre exact configurable :

Travailler avec la latence
Malgré tous nos efforts, il n'est pas facile de garantir un environnement sans latence. Le délai de réplication est habituellement de moins d'une seconde mais peut exceptionnellement s'étaler jusqu'à 30 secondes. Pour l'évolutivité, il est très important de maintenir la charge sur le master à un niveau bas, donc le fait d'envoyer simplement toutes vos requêtes au maître n'est pas une solution. Donc si vous avez absolument besoin de données à jour, nous vous proposons l'approche suivante :


 * 1) faites une requêtes rapide au master pour avoir un numéro de séquence ou une référence horaire
 * 2) exécutez la requête complète sur le réplicat et vérifiez si elle correspond aux données reçues du master
 * 3) si ce n'est pas le cas, exécutez la requête complète sur le master

Pour éviter de surcharger le master à chaque fois que les réplicats sont en retard, l'utilisation de cette approche doit être réduite au maximum. Dans la plupart des cas, lisez simplement sur le réplicat et laissez l'utilisateur gérer le retard.

Etreinte fatale
A cause de la fréquence très rapide des écritures sur Wikipedia (et sur certains autres wikis), les développeurs MediaWiki doivent faire très attention à structurer leurs écritures de sorte à éviter que les blocages ne s'éternisent. Par défaut, MediaWiki ouvre une transaction lors de la première requête, puis la valide (commit) avant que la sortie ne soit envoyée. Les verrous seront maintenus à partir du moment où la requête est faite et jusqu'à la validation (commit). Par conséquent vous pouvez réduire le temps de blocage en réalisant le maximum de traitement possible avant de lancer les requêtes d'écriture. Les opérations de mise à jour qui n'ont pas besoin de la base de données peuvent être repoussées jusqu'après le commit en ajoutant un objet à.

Souvent cette approche n'est pas idéale et il est nécessaire d'inclure de petits groupes de requêtes dans leur propre transaction. Utilisez la syntaxe suivante :

L'utilisation de verrous en lecture (par exemple avec l'option FOR UPDATE) n'est pas conseillée. Ils sont faiblement implémentés dans InnoDB et provoquent régulièrement des erreurs d'étreinte fatale. Il est également étonnamment facile de paralyser le wiki avec une contention de verrouillage.

Au lieu de verrouiller les lectures, combinez les vérifications d'existence dans vos requêtes d'écriture, en utilisant une condition appropriée dans la clause WHERE de UPDATE ou en utilisant des index uniques en combinaison avec INSERT IGNORE. Puis utilisez le nombre de lignes affecté pour voir si la requête s'est correctement exécutée.

Schéma de la base de données
N'oubliez pas les index quand vous concevez une base de données; il est possible que tout se passe à merveille sur votre wiki de test avec une dizaine de pages, mais que des blocages apparaissent sur le wiki réel. Voir ci-dessus pour les détails.

Pour les conventions de nommage, voir.

Compatibilité SQLite
Lorsque vous écrivez les définitions des tables MySQL ou les correctifs de mise à jour, il est important de se rappeler que SQLite partage le schéma de MySQL, mais cela ne fonctionne que si les définitions sont écrites d'une manière particulière :


 * les clés primaires doivent se trouver dans la déclaration de la table principale, et les clés ordinaires doivent être ajoutées séparément avec CREATE INDEX :

Néanmoins les clés primaires qui s'étendent sur plusieurs champs doivent être incluses dans la définition de la table principale :


 * n'ajoutez pas plus d'une colonne par instruction :


 * définissez les valeurs par défaut explicites quand vous ajoutez des colonnes NON NULLES :

Les contrôles de compatibilité de base peuvent être faits avec :



Ou, si vous avez besoin de tester une correction de mise à jour, avec simultanément :


 * (avec le nouveau tables.sql)
 * Parce que les correctifs de la base de données mettent à jour également le fichier tables.sql, pour celui-ci il faut passer la version de pré-validation de tables.sql (le fichier avec la définition complète de la base de données). Sinon vous pouvez obtenir une erreur si par exemple vous perdez un index (parce qu'il n'existe plus dans tables.sql car vous venez juste de le supprimer).
 * Parce que les correctifs de la base de données mettent à jour également le fichier tables.sql, pour celui-ci il faut passer la version de pré-validation de tables.sql (le fichier avec la définition complète de la base de données). Sinon vous pouvez obtenir une erreur si par exemple vous perdez un index (parce qu'il n'existe plus dans tables.sql car vous venez juste de le supprimer).

Ce qui précède suppose que vous êtes dans $IP/maintenance/, sinon passez le chemin complet du ficher. Pour les correctifs des extensions, utiliser l'équivalent de ces fichiers pour les extensions.

Voir aussi

 * &mdash; Si une extension a besoin de modifications dans la base de données alors que MediaWiki est en cours de mise à jour, cela peut se faire via cette accroche. Les utilisateurs peuvent ensuite mettre à jour leur wiki en exécutant.