Est-ce que l'ordre des colonnes dans un index PK est important?
Oui.
Par défaut, la contrainte de clé primaire est appliquée dans SQL Server par un index en cluster unique. L'index clusterisé définit l' ordre logique des lignes de la table. Un certain nombre de pages d'index supplémentaires peuvent être ajoutées pour représenter les niveaux supérieurs de l'index b-tree, mais le niveau le plus bas (feuille) d'un index en cluster correspond simplement à l'ordre logique des données.
Pour être clair, les lignes d'une page ne sont pas nécessairement stockées physiquement dans l'ordre des clés d'index en cluster. Il existe une structure distincte d'indirection dans la page qui stocke un pointeur sur chaque ligne. Cette structure est triée par les clés d'index en cluster. De plus, chaque page a un pointeur sur la page précédente et la page suivante au même niveau dans l'ordre de la clé d'index en cluster.
Avec une clé primaire en cluster de (RowNumber, DataDate)
, les lignes sont triées de manière logique en premier RowNumber
, puis en DataDate
- de manière à ce que toutes les lignes RowNumber = 1
soient logiquement regroupées, puis les lignes où RowNumber = 2
, etc.
Lorsque vous ajoutez de nouvelles données (avec RowNumbers
de 1 à n), les nouvelles lignes appartiennent logiquement à l'intérieur des pages existantes. SQL Server devra donc probablement effectuer de nombreuses opérations de fractionnement des pages pour libérer de l'espace. Toute cette activité génère beaucoup de travail supplémentaire (y compris la consignation des modifications) sans aucun gain.
Les pages divisées démarrent également à environ 50% vides. Par conséquent, une division excessive peut entraîner une densité de page faible (moins de lignes que la valeur optimale par page). Non seulement cette mauvaise nouvelle pour la lecture à partir du disque (faible densité = plus de pages à lire), mais les pages à faible densité prennent également plus de place en mémoire lors de la mise en cache.
Si vous modifiez l’index clusterisé en (DataDate, RowNumber
), cela signifie que les nouvelles données (avec, vraisemblablement, plus DataDates
que ce qui est actuellement stocké) sont ajoutées à la fin logique de l’index clusterisé sur les nouvelles pages. Cela supprime les frais généraux inutiles liés au fractionnement des pages et accélère les temps de chargement. Des données moins fragmentées signifient également qu'une activité de lecture à l'avance (lire des pages d'un disque juste avant de les utiliser pour une requête en cours) peut être plus efficace.
Si rien d'autre, vos questions sont beaucoup plus susceptibles de rechercher DataDate
que RowNumber
. Un index en cluster sur (DataDate, RowNumber
) prend en charge la recherche d’index sur DataDate
(puis RowNumber
). Le dispositif existant ne prend en charge que les recherches sur RowNumber
(et seulement alors, peut-être sur DataDate
). Vous pourrez peut-être supprimer l'index non cluster existant DataDate
une fois que la clé primaire aura été modifiée. L'index clusterisé sera plus large que l'index non clusterisé qu'il remplace. Vous devez donc effectuer un test pour vous assurer que les performances restent acceptables.
Lors de l'importation de nouvelles données avec bcp
, vous pouvez obtenir de meilleures performances si les données du fichier d'importation sont triées par les clés d'index en cluster (idéalement (DataDate, RowNumber
) et que vous spécifiez l' bcp
option suivante:
-h "ORDER(DataDate,RowNumber), TABLOCK"
Pour optimiser les performances de chargement des données, vous pouvez essayer de réaliser des insertions journalisées de manière minimale. Pour plus d'informations, voir: