Dans Dynamics AX, il existe un mécanisme de mise en cache dans lequel les tables peuvent être configurées pour être chargées en mémoire et mises en cache. Ce cache est limité à une certaine quantité de Ko pour éviter les problèmes de mémoire. Le paramètre dont je parle est appelé entiretablecache
et charge toute la table en mémoire dès qu'un seul enregistrement est demandé.
Jusqu'à récemment, nous nous sommes appuyés sur certains scripts pour vérifier la taille des tables qui ont ce paramètre pour voir si la taille de la table est supérieure à cette limite.
Maintenant cependant, la compression entre en jeu et des choses comme sp_spaceused ou sys.allocation_units semblent signaler l'espace réellement utilisé par les données compressées.
De toute évidence, le serveur d'applications fonctionne avec des données non compressées, de sorte que la taille des données sur le disque dans SQL Server n'est pas pertinente. J'ai besoin de la taille réelle des données non compressées.
Je connais sp_estimate_data_compression_savings mais comme son nom l'indique, ce n'est qu'une estimation.
Je préférerais avoir une taille aussi correcte que possible.
La seule façon dont je pouvais penser était un SQL dynamique alambiqué créant des tables non compressées avec la même structure que les tables compressées, insérant les données compressées dans cette table fantôme, puis vérifiant la taille de cette table fantôme.
Inutile de dire que cela est un peu fastidieux et prend du temps pour fonctionner sur une base de données de plusieurs centaines de Go.
Powershell pourrait être une option, mais je ne voudrais pas parcourir toutes les tables pour effectuer une select *
sur elles pour vérifier la taille dans le script car cela inonderait simplement le cache et prendrait probablement aussi beaucoup de temps.
En bref, j'ai besoin d'un moyen d'obtenir la taille de chaque table car elle sera une fois non compressée et avec une fragmentation hors de l'équation telle que présentée à l'application, si cela est possible. Je suis ouvert à différentes approches, T-SQL est préféré mais je ne suis pas opposé à Powershell ou à d'autres approches créatives.
Supposons que le tampon dans l'application correspond à la taille des données. Un bigint est toujours la taille d'un bigint, et un type de données de caractère est de 2 octets par caractère (unicode). Les données BLOB prennent également la taille des données, une énumération est fondamentalement un entier et les données numériques sont numériques (38,12), datetime est la taille d'un datetime. De plus, il n'y a pas de NULL
valeurs, elles sont soit stockées sous forme de chaîne vide, 1900-01-01
soit zéro.
Il n'y a pas de documentation sur la façon dont cela est implémenté, mais les hypothèses sont basées sur certains tests et les scripts utilisés par les PFE et l'équipe de support (qui ignorent également la compression apparemment, car la vérification est intégrée dans l'application et l'application ne peut pas le dire si les données sous-jacentes sont compressées) qui vérifient également les tailles de table. Ce lien indique par exemple:
Évitez d'utiliser des caches de table entière pour les tables volumineuses (dans AX 2009 sur 128 Ko ou 16 pages, dans AX 2012 sur le paramètre d'application 'taille de cache de table entière' [par défaut: 32 Ko, ou 4 pages]) - passez à la mise en cache des enregistrements à la place.
la source
Réponses:
Alors que le désir de cette information est certainement compréhensible, obtenir cette information, en particulier dans le contexte de «corriger le plus possible» est plus difficile que tout le monde attend en raison d'hypothèses erronées. Que ce soit en faisant l'idée de la table fantôme non compressée mentionnée dans la question, ou la suggestion de @ sp_BlitzErik dans un commentaire sur la restauration de la base de données et la décompression là pour vérifier, il ne faut pas supposer que la taille de la table non compressée == la taille desdites données en mémoire sur le serveur d'applications:
Sont toutes les lignes de la table étant mises en cache? Ou tout simplement dans une plage? L'hypothèse ici est qu'il est tout, et que peut - être correct, mais je me suis dit qu'il devrait au moins mentionner que ce pourrait ne pas être le cas ( à moins que la documentation indique le contraire, mais cela est un point mineur de toute façon, ne voulait pas à ne pas mentionner).
La question a été mise à jour pour indiquer: oui, toutes les lignes sont mises en cache.
Frais généraux de structure
page et surcharge de lignes côté DB: le nombre de lignes qui tiennent sur une page est déterminé par de nombreux facteurs susceptibles de perturber les estimations. Même avec un
FILLFACTOR
de 100 (ou 0), il reste probablement de l'espace inutilisé sur la page car il ne suffit pas pour une ligne entière. Et cela s'ajoute à l'en-tête de page. De plus, si une fonctionnalité d'isolement de capture instantanée est activée, il y aura, je crois, 13 octets supplémentaires par ligne occupés par le numéro de version, ce qui annulera les estimations. Il existe d'autres détails liés à la taille réelle de la ligne (bitmap NULL, colonnes de longueur variable, etc.), mais les éléments mentionnés jusqu'à présent devraient à eux seuls faire le point.quel type de collection est utilisé pour stocker les résultats mis en cache? Je suppose que c'est une application .NET, est-ce donc un
DataTable
? Une liste générique? Un SortedDictionary? Chaque type de collection a une quantité différente d'entendu. Je ne m'attendrais pas à ce que l'une des options reflète nécessairement les frais généraux de page et de ligne du côté DB, en particulier à l'échelle (je suis sûr qu'une petite quantité de ligne pourrait ne pas avoir assez de divers pour avoir de l'importance, mais vous ne recherchez pas de différences en centaines d'octets ou juste quelques ko).CHAR
/VARCHAR
data est stocké à 1 octet par caractère (en ignorant pour l'instant les caractères à double octet).XML
est optimisé pour ne pas prendre autant d’espace que la représentation du texte l’implique. Ce type de données crée un dictionnaire de noms d'éléments et d'attributs et remplace les références réelles à eux dans le document par leurs ID respectifs (plutôt sympa, en fait). Sinon, les valeurs de chaîne sont toutes en UTF-16 (2 ou 4 octets par "caractère"), tout commeNCHAR
/NVARCHAR
.DATETIME2
est compris entre 6 et 8 octets.DECIMAL
est compris entre 5 et 17 octets (selon la précision).chaînes (encore une fois, en supposant que .NET) sont toujours UTF-16. Il n'y a pas d'optimisation pour les chaînes 8 bits telles que ce qui
VARCHAR
est valable. MAIS, les chaînes peuvent également être "internées" qui est une copie partagée qui peut être référencée plusieurs fois (mais je ne sais pas si cela fonctionne pour les chaînes dans les collections, ou si oui, si cela fonctionne pour tous les types de collections).XML
peut ou non être stocké de la même manière dans la mémoire (je devrai le vérifier).DateTime
est toujours 8 octets (comme T-SQLDATETIME
, mais pas commeDATE
,TIME
ouDATETIME2
).Decimal
est toujours de 16 octets .Tout cela pour dire: il n'y a pratiquement rien que vous puissiez faire du côté DB pour gagner une taille d'empreinte mémoire même assez précise du côté du serveur d'applications. Vous devez trouver un moyen d'interroger le serveur d'application lui-même, après avoir été chargé avec une table particulière, alors sachez quelle est sa taille. Et je ne sais pas si un débogueur vous permettrait de voir la taille d'exécution d'une collection remplie. Sinon, la seule façon de se rapprocher serait de parcourir toutes les lignes d'un tableau, en multipliant chaque colonne par la taille .NET appropriée (par exemple
INT
=* 4
,VARCHAR
=DATALENGTH() * 2
,NVARCHAR
=DATALENGTH()
,XML
= 🙃, etc.), mais cela laisse toujours la question des frais généraux de la collection plus chaque élément de la collection.Étant donné une nouvelle définition dans la question, on pourrait probablement faire la requête suivante pour être assez proche. Et peu importe que la table soit compressée ou non, bien que c'est à chaque personne de déterminer si l'analyse de toutes les lignes est appropriée en production (peut-être à partir d'une restauration ou pendant les heures creuses):
Mais rappelez-vous, cela ne tient pas compte des frais généraux de collection ou d'élément de collection. Et je ne sais pas si nous pouvons obtenir cette valeur sans débogueur (ou peut-être quelque chose comme ILSpy, mais je ne le recommande pas car cela pourrait violer le CLUF en fonction des lois locales).
la source
D'après votre question, il semble que vous ayez une taille de cache maximale
S
et que vous ne souhaitiez pas charger dans le cache des tables qui dépassent cette taille. Si c'est vrai, vous n'avez pas besoin de connaître la taille exacte de chaque table. Vous avez juste besoin de savoir si une table est plus grande ou plus petite que la taille maximale du cacheS
. C'est un problème beaucoup plus facile selon les définitions de colonne et le nombre de lignes de vos tables.Je suis d'accord avec la grande réponse de Solomon Rutzky en ce sens que regarder des données non compressées n'est pas la voie à suivre et qu'il pourrait être difficile de trouver une bonne approximation de la taille réelle d'une table dans le cache. Cependant, je vais travailler dans le cadre de la question et supposer que vous pouvez développer une formule suffisamment proche en fonction des définitions de colonne pour les types de données statiques et de la longueur réelle de vos colonnes dynamiques.
Si vous avez ce mappage des types de données à la taille du cache, vous devriez être en mesure d'évaluer certaines tables sans même regarder les données qu'elles contiennent:
sys.partitions
et en calculant la taille de la table à l'aide des définitions de colonne.BIGINT
colonnes pourrait avoir la taille de ces données de 10000000 * (8 + 8 + 8 + 8 + 8) = 400 M octets, ce qui pourrait être supérieur à la taille limite de votre cacheS
. Ce n'est pas grave s'il a aussi un tas de colonnes de chaînes.BIGINT
colonne et uneNVARCHAR(20)
colonne ne doit pas dépasser 100 * (8 + 2 * 20) = 4800 octets.S
, il est très peu probable qu'elle tienne dans le cache. Vous devriez faire des tests pour déterminer si une telle valeur existe.Vous devrez peut-être interroger les données des tables qui ne correspondent à aucun des critères ci-dessus. Il existe quelques astuces que vous pouvez utiliser pour minimiser l'impact sur les performances de cela. Je dirais que vous avez ici deux priorités concurrentes: vous appréciez la précision, mais vous ne voulez pas non plus analyser toutes les données de votre base de données. Il peut être possible d'ajouter une sorte de tampon à vos calculs. Je ne sais pas s'il est plus acceptable d'exclure une table légèrement inférieure à la taille maximale du cache
S
ou d'inclure une table légèrement supérieure à la taille maximale du cache.Voici quelques idées pour accélérer les requêtes qui examinent les données de table:
TABLESAMPLE
à condition que la taille de votre échantillon soit suffisamment grande.SUM()
qui se termine tôt en fonction de la valeur de cet agrégat. Je n'ai vu que ça fonctionnerROW_NUMBER()
. Mais vous pouvez numériser les 10 premiers% du tableau, enregistrer la taille des données calculées, numériser les 10% suivants, etc. Pour les tables trop volumineuses pour le cache, vous pouvez peut-être économiser une quantité importante de travail avec cette approche en quittant tôt.Je me rends compte que je n'ai inclus aucun code SQL dans cette réponse. Faites-moi savoir s'il serait utile d'écrire du code de démonstration pour l'une des idées que j'ai discutées ici.
la source