web-dev-qa-db-fra.com

Stockage des données encodées en base64 en tant que type de données BLOB ou TEXT

Nous avons une table MySQL InnoDB contenant environ 10 colonnes de petits fichiers javascript encodés en base64 et des images png (<2 Ko) base64 encodées également.

Il y a peu d'insertions et beaucoup de lectures comparativement, cependant la sortie est mise en cache sur une instance Memcached pendant quelques minutes pour éviter les lectures suivantes.

Dans l'état actuel des choses, nous utilisons BLOB pour ces colonnes, mais je me demande s'il y a un avantage à passer au type de données TEXT en termes de performances ou de sauvegarde d'instantanés.

Mes recherches indiquent que BLOB et TEXT pour mon cas sont presque identiques et comme je ne sais pas au préalable quel type de données va réellement être stocké, j'ai choisi BLOB.

Avez-vous des conseils sur le débat TEXT vs BLOB pour ce cas spécifique?

17

Il ne faut pas stocker de données encodées en Base64 dans sa base de données ...

Base64 est un moyen de représenter des données binaires arbitraires en utilisant uniquement des caractères de texte imprimables: il a été conçu pour les situations où l'on a besoin de transférer ces données binaires via un protocole ou un support qui ne peut gérer que du texte imprimable (par exemple SMTP/email). Il augmente la taille des données (de 33%) et ajoute le coût de calcul du codage/décodage, il convient donc de l'éviter sauf en cas de nécessité absolue.

En revanche, tout l'intérêt des colonnes BLOB est qu'elles stockent des chaînes binaires brutes . Alors, allez-y et stockez votre contenu directement dans vos colonnes BLOB sans d'abord les encoder en Base64. Habituellement, vous souhaiterez stocker les métadonnées associées dans d'autres colonnes, telles que la version du fichier/la date de dernière modification, le type de support et (dans le cas des fichiers texte, tels que les sources JavaScript) le codage des caractères. Vous pouvez décider d'utiliser des colonnes de type TEXT pour les fichiers texte, non seulement pour que MySQL suive nativement l'encodage des caractères pour vous, mais aussi pour qu'il puisse transcoder vers d'autres jeux de caractères et/ou inspecter/manipuler le texte selon les besoins (maintenant ou à l'avenir).

L'idée (erronée) que les bases de données SQL nécessitent des encodages de texte imprimable comme Base64 pour gérer des données binaires arbitraires a été perpétuée par un grand nombre de didacticiels mal informés. Cette idée semble reposer sur la croyance erronée que, parce que SQL ne comprend que du texte imprimable dans d'autres contextes, il doit sûrement l'exiger également pour les données binaires (au moins pour le transfert de données, sinon pour le stockage de données). Ce n'est tout simplement pas vrai: SQL peut transmettre des données binaires de plusieurs façons, y compris des littéraux de chaîne simples (à condition qu'ils soient correctement cités et échappés comme toute autre chaîne); bien sûr, la façon préférée de transmettre des données (de tout type) à votre base de données est par le biais de requêtes paramétrées, et les paramètres peuvent tout aussi facilement contenir des données binaires qu'ils ne le peuvent.

Pour ce que ça vaut, j'évite généralement de stocker des éléments comme celui-ci dans le SGBDR et préfère plutôt utiliser ces bases de données de stockage de fichiers hautement optimisées appelées systèmes de fichiers - mais c'est une tout autre affaire.

... sauf s'il est mis en cache pour des raisons de performances ...

La seule situation dans laquelle le stockage de données encodées en Base64 pourrait être un avantage est que les données sont fréquemment récupérées de la base de données et transmises via un protocole qui nécessite cet encodage. Dans ce cas, le stockage de la représentation encodée en Base64 éviterait d'avoir à effectuer l'opération de codage sur les données autrement brutes à chaque extraction.

Cependant, notez dans ce sens que le stockage encodé en Base64 agit simplement comme un cache , tout comme on pourrait stocker des données dénormalisées pour des raisons de performances.

... auquel cas ce doit être TEXT pas BLOB

Comme mentionné ci-dessus, la différence entre TEXT et BLOB se résume vraiment au fait que les colonnes TEXT sont stockées avec des métadonnées spécifiques au texte (telles que codage des caractères et classement ), contrairement aux colonnes BLOB. Ces métadonnées supplémentaires permettent à MySQL de transcoder des caractères entre les jeux de caractères de stockage et de connexion (le cas échéant) et d'effectuer l'équivalence/l'ordre des caractères fantaisistes.

De manière générale: si deux clients travaillant dans des jeux de caractères différents doivent voir les mêmes octets , alors vous voulez une colonne BLOB; s'ils doivent voir les mêmes caractères , alors vous voulez une colonne TEXT.

Avec Base64, ces deux clients doivent finalement trouver que les données décodent dans les mêmes octets ; mais ils devraient voir que les données codées ont les mêmes caractères . Par exemple, supposons que l'on souhaite insérer l'encodage Base64 de 'Hello world!' (lequel est 'SGVsbG8Gd29ybGQh'). Si l'application d'insertion fonctionne dans le jeu de caractères UTF-8, elle enverra la séquence d'octets 0x53475673624738676432397962475168 à la base de données.

  • si cette séquence d'octets est stockée dans une colonne BLOB et récupérée ultérieurement par une application qui fonctionne en UTF-16*, les mêmes octets seront retournés — ce qui représente '升噳扇㡧搲㥹扇全' et non la valeur encodée en Base64 souhaitée; tandis que

  • si cette séquence d'octets est stockée dans une colonne TEXT et récupérée ultérieurement par une application qui fonctionne en UTF-16, MySQL transcodera à la volée pour renvoyer la séquence d'octets 0x0053004700560073006200470038006700640032003900790062004700510068— qui représente la valeur d'origine codée en Base64 'SGVsbG8Gd29ybGQh' comme voulu.

Bien sûr, vous pouvez néanmoins utiliser les colonnes BLOB et suivre l'encodage des caractères d'une autre manière, mais cela réinventerait simplement la roue, avec une complexité de maintenance accrue et le risque d'introduire des erreurs involontaires.


* En fait, MySQL ne prend pas en charge l'utilisation de jeux de caractères clients qui ne sont pas compatibles avec l'octet avec ASCII (et donc les encodages Base64 seront toujours cohérents dans n'importe quelle combinaison d'entre eux), mais cet exemple sert néanmoins à illustrent la différence entre les types de colonnes BLOB et TEXT et expliquent ainsi pourquoi TEXT est techniquement correct à cet effet, même si BLOB fonctionnera réellement sans erreur (à au moins jusqu'à ce que MySQL ajoute la prise en charge des jeux de caractères clients non compatibles ASCII).

43
eggyal