Réponse simple :NON. Vous ne pouvez pas aider les requêtes ad hoc sur une table de 238 colonnes avec un facteur de remplissage de 50 % sur l'index clusterisé.
Réponse détaillée :
Comme je l'ai dit dans d'autres réponses sur ce sujet, la conception de l'index est à la fois un art et une science et il y a tellement de facteurs à prendre en compte qu'il y a peu de règles strictes, voire aucune. Vous devez prendre en compte :le volume des opérations DML par rapport aux SELECT, le sous-système de disque, les autres index/déclencheurs sur la table, la distribution des données dans la table, les requêtes utilisant les conditions SARGable WHERE, et plusieurs autres choses dont je ne me souviens même pas correctement maintenant.
Je peux dire qu'aucune aide ne peut être donnée pour les questions sur ce sujet sans une compréhension de la table elle-même, de ses index, déclencheurs, etc. Maintenant que vous avez posté la définition de table (toujours en attente sur les index mais la définition de table seule pointe vers 99 % du problème) Je peux proposer quelques suggestions.
Tout d'abord, si la définition du tableau est précise (238 colonnes, 50 % de facteur de remplissage), vous pouvez à peu près ignorer le reste des réponses/conseils ici ;-). Désolé d'être moins que politique ici, mais sérieusement, c'est une chasse à l'oie sauvage sans connaître les détails. Et maintenant que nous voyons la définition de la table, il devient un peu plus clair pourquoi une requête simple prendrait si longtemps, même lorsque les requêtes de test (Mise à jour #1) s'exécutaient si rapidement.
Le principal problème ici (et dans de nombreuses situations de mauvaise performance) est une mauvaise modélisation des données. 238 colonnes n'est pas interdit tout comme avoir 999 index n'est pas interdit, mais ce n'est aussi généralement pas très judicieux.
Recommandations :
- Tout d'abord, cette table a vraiment besoin d'être remodelée. S'il s'agit d'une table d'entrepôt de données, alors peut-être, mais sinon, ces champs doivent vraiment être divisés en plusieurs tables qui peuvent toutes avoir le même PK. Vous auriez une table d'enregistrement principale et les tables enfants ne sont que des informations dépendantes basées sur des attributs couramment associés et le PK de ces tables est le même que le PK de la table principale et donc également FK à la table principale. Il y aura une relation 1 à 1 entre le maître et toutes les tables enfants.
- L'utilisation de
ANSI_PADDING OFF
est dérangeant, sans parler des incohérences dans le tableau en raison des divers ajouts de colonnes au fil du temps. Je ne sais pas si vous pouvez résoudre ce problème maintenant, mais idéalement, vous auriez toujoursANSI_PADDING ON
, ou à tout le moins avoir le même paramètre sur tous lesALTER TABLE
déclarations. - Envisagez de créer 2 groupes de fichiers supplémentaires :les tables et les index. Il est préférable de ne pas mettre vos affaires en
PRIMARY
car c'est là que SQL SERVER stocke toutes ses données et métadonnées sur vos objets. Vous créez votre table et votre index clusterisé (car ce sont les données de la table) sur[Tables]
et tous les index non clusterisés sur[Indexes]
- Augmentez le facteur de remplissage de 50 %. Ce faible nombre est probablement la raison pour laquelle votre espace d'index est plus grand que votre espace de données. Faire une reconstruction d'index recréera les pages de données avec un maximum de 4k (sur la taille totale de page de 8k) utilisées pour vos données afin que votre table soit répartie sur une large zone.
- Si la plupart ou la totalité des requêtes comportent "ER101_ORG_CODE" dans
WHERE
condition, puis envisagez de la déplacer vers la colonne de tête de l'index clusterisé. En supposant qu'il soit utilisé plus souvent que "ER101_ORD_NBR". Si "ER101_ORD_NBR" est utilisé plus souvent, conservez-le. Il semble simplement, en supposant que les noms de champ signifient "OrganizationCode" et "OrderNumber", que "OrgCode" est un meilleur regroupement qui pourrait contenir plusieurs "OrderNumbers". - Point mineur, mais si "ER101_ORG_CODE" est toujours composé de 2 caractères, alors utilisez
CHAR(2)
au lieu deVARCHAR(2)
car cela permettra d'économiser un octet dans l'en-tête de ligne qui suit les tailles de largeur variables et s'additionne sur des millions de lignes. - Comme d'autres l'ont mentionné ici, en utilisant
SELECT *
nuira aux performances. Non seulement parce que SQL Server doit renvoyer toutes les colonnes et donc être plus susceptible d'effectuer une analyse d'index clusterisée quels que soient vos autres index, mais cela prend également du temps à SQL Server pour accéder à la définition de la table et traduire*
dans tous les noms de colonne. Il devrait être légèrement plus rapide pour spécifier les 238 noms de colonne dans leSELECT
liste bien que cela n'aidera pas le problème de numérisation. Mais avez-vous déjà vraiment besoin des 238 colonnes en même temps ?
Bonne chance !
MISE À JOUR
Par souci d'exhaustivité à la question "comment améliorer les performances sur une grande table pour les requêtes ad hoc", il convient de noter que même si cela n'aidera pas pour ce cas spécifique, SI quelqu'un utilise SQL Server 2012 (ou plus récent le moment venu) et SI la table n'est pas mise à jour, l'utilisation des index Columnstore est une option. Pour plus de détails sur cette nouvelle fonctionnalité, regardez ici :http://msdn.microsoft.com/en-us/library/gg492088.aspx (je crois qu'ils ont été conçus pour être mis à jour à partir de SQL Server 2014).
MISE À JOUR 2
Les considérations supplémentaires sont :
- Activer la compression sur l'index clusterisé. Cette option est devenue disponible dans SQL Server 2008, mais en tant que fonctionnalité réservée à Enterprise Edition. Cependant, à partir de SQL Server 2016 SP1 , la compression des données est disponible dans toutes les éditions ! Veuillez consulter la page MSDN pour la compression des données pour plus de détails sur la compression des lignes et des pages.
- Si vous ne pouvez pas utiliser la compression de données, ou si elle n'offre pas beaucoup d'avantages pour une table particulière, alors SI vous avez une colonne de type à longueur fixe (
INT
,BIGINT
,TINYINT
,SMALLINT
,CHAR
,NCHAR
,BINARY
,DATETIME
,SMALLDATETIME
,MONEY
, etc) et bien plus de 50 % des lignes sontNULL
, puis envisagez d'activer leSPARSE
option qui est devenue disponible dans SQL Server 2008. Veuillez consulter la page MSDN pour utiliser les colonnes éparses pour plus de détails.