Le nombre de champs dans une table affecte-t-il les performances même s'ils ne sont pas référencés?

Je lis et parsing les files CSV dans une database SQL Server 2008. Ce process utilise un parsingur CSV générique pour tous les files.

L'parsingur CSV place les champs analysés dans une table générique d'import de champs (F001 VARCHAR (MAX) NULL, F002 VARCHAR (MAX) NULL, Fnnn …) qu'un autre process déplace ensuite dans de vraies tables en utilisant le code SQL qui sait quel champ analysé (Fnnn) va à quel champ dans la table de destination. Ainsi, une fois dans la table, seuls les champs en cours de copy sont référencés. Certains files peuvent être assez volumineux (un million de lignes).

La question est: le nombre de champs dans une table affecte-t-il significativement les performances ou l'utilisation de la memory? Même si la plupart des champs ne sont pas référencés. Les seules opérations effectuées sur les tables d'import de champs sont un INSERT, puis un SELECT pour déplacer datatables dans une autre table, il n'y a pas de JOINs ou de WHERE sur datatables du champ.

Actuellement, j'ai trois tables d'import de champs, une avec 20 champs, une avec 50 champs et une avec 100 champs (ceci étant le nombre maximum de champs que j'ai rencontrés jusqu'ici). Il est actuellement logique d'utiliser le plus petit file possible.

Je voudrais rendre ce process plus générique, et avoir une seule table de 1000 champs (je suis conscient de la limite de 1024 colonnes). Et oui, certains des files planifiés à traiter (provenant de tierces parties) seront dans la plage de 900-1000.

Pour la plupart des files, il y aura less de 50 champs.

À ce stade, traiter les trois tables d'import de champs existantes (plus les tables prévues pour plus de champs (200,500,1000?)) Devient un cauchemar logistique dans le code, et traiter une table unique résoudrait beaucoup de problèmes, à condition N'abandonnez pas beaucoup de performance.

Comme cela a été correctement souligné dans les commentaires, même si votre table contient 1000 colonnes, mais que la plupart d'entre elles sont NULL , cela ne devrait pas beaucoup affecter les performances, car les NULLs ne gaspilleront pas beaucoup d'espace.

Vous avez mentionné que vous pouvez avoir des données réelles avec 900-1000 colonnes non-NULL. Si vous prévoyez d'importer de tels files, vous pouvez rencontrer une autre limitation de SQL Server. Oui, le nombre maximal de colonnes dans une table est 1024, mais il existe une limite de 8060 octets par ligne . Si vos colonnes sont varchar (max), alors chacune de ces colonnes consumra 24 octets sur 8060 dans la ligne actuelle et le rest des données sera poussé hors-ligne:

SQL Server prend en charge le stockage de débordement de ligne, ce qui permet de pousser les colonnes de longueur variable hors ligne. Seule une racine de 24 octets est stockée dans l'logging principal pour les colonnes de longueur variable poussées hors ligne; Pour cette raison, la limite de ligne effective est plus élevée que dans les versions précédentes de SQL Server. Pour plus d'informations, consultez la rubrique «Row Overflow Data dépassant 8 Ko» dans la documentation en ligne de SQL Server.

Donc, en pratique, vous pouvez avoir une table avec seulement 8060 / 24 = 335 colonnes non NULL (max). (Ssortingctement parlant, même un peu less, il y a aussi d'autres en-têtes).

Il existe des tables étendues pouvant contenir jusqu'à 30 000 colonnes, mais la taille maximale de la ligne de la table large est de 8 019 octets. Donc, ils ne vont pas vraiment vous aider dans ce cas.

Oui. les loggings volumineux occupent plus d'espace sur le disque et en memory, ce qui signifie que leur chargement est plus lent que les loggings de taille réduite et que less d'entre eux peuvent entrer en memory. les deux effets vont nuire à la performance.

Tout d'abord, pour répondre à la question:

Le nombre de champs dans une table affecte-t-il les performances même s'ils ne sont pas référencés?

  • Si les champs sont de longueur fixe (* INT, * MONEY, DATE / HEURE / DATETIME / etc, UNIQUEIDENTIFIER, etc) ET que le champ n'est pas marqué SPARSE ou que la compression n'a pas été activée (les deux démarrés dans SQL Server 2008), alors la taille totale du champ est prise en count (même si NULL ) et cela affecte les performances, même si les champs ne sont pas dans la list SELECT.

  • Si les champs sont de longueur variable et NULL (ou vide), ils prennent juste un peu d'espace dans l'en-tête de page.

  • En ce qui concerne l'espace en général, cette table est-elle un tas (pas d'index clusterisé) ou en cluster? Et comment nettoyez-vous la table pour chaque nouvelle import? Si c'est un tas et que vous êtes en train de faire un DELETE , alors il ne sera peut-être pas débarrasser de toutes les pages inutilisées. Vous savez s'il y a un problème en voyant l'espace occupé même avec 0 lignes en faisant sp_spaceused . Les suggestions 2 et 3 ci-dessous n'auraient naturellement pas un tel problème.

Maintenant, quelques idées:

  1. Avez-vous envisagé d'utiliser SSIS pour gérer cela dynamicment?

  2. Puisque vous semblez avoir un process à un seul thread, pourquoi ne pas créer une table temporaire globale au début du process à chaque fois? Ou, abandonner et recréer une vraie table dans tempdb ? Quoi qu'il en soit, si vous connaissez la destination, vous pouvez même créer dynamicment cette table d'import avec les noms de champs de destination et les types de données. Même si l'importateur CSV ne connaît pas la destination, au début du process, vous pouvez appeler un proc qui connaîtrait la destination, créer la table "temp", puis l'importateur peut toujours importer de façon générique dans une norme nom de la table sans champ spécifié et pas d'erreur si les champs de la table sont NULLable et sont au less autant qu'il y a de colonnes dans le file.

  3. Les données CSV entrantes comportent-elles des returns, des guillemets et / ou des délimiteurs embeddeds? Maniez-vous datatables entre la table de transfert et la table de destination? Il pourrait être possible d'importer dynamicment directement dans la table de destination, avec des types de données appropriés, mais pas de manipulation en transit. Une autre option est de le faire dans SQLCLR. Vous pouvez écrire une procédure stockée pour ouvrir un file et cracher les champs de division en effectuant un INSERT INTO...EXEC . Ou, si vous ne voulez pas écrire le vôtre, jetez un oeil à la bibliothèque SQL # SQLCLR, en particulier la procédure stockée File_SplitIntoFields . Ce proc n'est disponible que dans la version Full / pay-for, et je suis le créateur de SQL #, mais il semble parfaitement adapté à cette situation.

  4. Étant donné que:

    • tous les champs sont importés en tant que text
    • les noms de champs de destination et les types sont connus
    • nombre de champs diffère entre les tables de destination

    Qu'en est-il d'avoir un seul champ XML et d'importer chaque ligne comme un document à un seul niveau, chaque champ étant <F001> , <F002> , etc.? En faisant cela, vous n'avez pas à vous soucier du nombre de champs ou des champs inutilisés. Et en fait, puisque les noms des champs de destination sont connus du process, vous pouvez même utiliser ces noms pour nommer les éléments du document XML pour chaque ligne. Ainsi, les lignes pourraient ressembler à:

     ID LoadFileID ImportLine 1 1 <row><FirstName>Bob</FirstName><LastName>Villa</LastName></row> 2 1 <row><Number>555-555-5555</Number><Type>Cell</Type></row> 

    Oui, datatables elles-mêmes occuperont plus d'espace que les champs VARCHAR (MAX) actuels, à la fois parce que XML est à double octet et parce que l'encombrement inhérent des balises d'éléments commence par. Mais alors vous n'êtes pas enfermé dans une structure physique. Et en regardant datatables, il sera plus facile d'identifier les problèmes puisque vous regarderez les noms de champs réels au lieu de F001, F002, etc.

  5. Pour accélérer au less le process de lecture du file, de division des champs et d'insertion, vous devez utiliser les parameters TVP (Table-Valued Parameters) pour diffuser datatables dans la table d'import. J'ai quelques réponses ici qui montrent différentes implémentations de la méthode, différant principalement en fonction de la source des données (file vs une collection déjà en memory, etc):

    • Comment puis-je insert 10 millions d'loggings dans les plus brefs timeouts?
    • Passez le dictionary <ssortingng, int> à la procédure stockée T-SQL
    • Stocker un dictionary <int, ssortingng> ou KeyValuePair dans une database