web-dev-qa-db-fra.com

Quelle est l'architecture d'index appropriée lorsqu'elle est forcée d'implémenter IsDeleted (suppressions en douceur)?

Actuellement, nous avons une base de données et une application existantes qui sont entièrement fonctionnelles. Je n'ai pas la possibilité de changer l'architecture à ce stade. Aujourd'hui, chaque table de la base de données possède un champ "IsDeleted" NOT NULL BIT avec une valeur par défaut de "0". Lorsque l'application "supprime" les données, elle met simplement à jour l'indicateur IsDeleted à 1.

Ce que j'ai du mal à comprendre, c'est comment les index de chacune des tables doivent être structurés. À l'heure actuelle, chaque requête/jointure/etc implémente toujours la vérification IsDeleted. C'est une norme que nos développeurs doivent suivre. Cela étant dit, j'essaie de déterminer si tous mes index de clé primaire en cluster sur chacune des tables doivent être modifiés pour inclure la clé primaire ET le champ IsDeleted BIT. De plus, puisque CHAQUE requête/jointure/etc. doit implémenter la vérification IsDeleted, est-ce une hypothèse appropriée que CHAQUE index SINGLE (non cluster également) devrait inclure le champ IsDeleted comme premier champ de l'index?

Une autre question que je me pose concerne les index filtrés. Je comprends que je pourrais mettre des filtres sur les index tels que "WHERE IsDeleted = 0" pour réduire la taille des index. Cependant, puisque chaque jointure/requête devra implémenter la vérification IsDeleted, cela empêcherait-il l'utilisation de l'index filtré (puisque la colonne IsDeleted est utilisée dans la jointure/requête)?

N'oubliez pas que je n'ai pas la possibilité de modifier l'approche IsDeleted.

17
Jerad Skinner

L'approche la plus simple consiste à laisser vos clés et index clusterisés seuls, et à utiliser des index filtrés pour vos index non clusterisés.

De plus, vous pouvez migrer certaines grandes tables vers des segments de partition ou des magasins de colonnes en cluster partitionnés (SQL Server 2016+), en laissant la clé primaire et les index uniques non partitionnés. Cela vous permettrait de pousser les colonnes non clés des lignes IsDeleted vers une structure de données distincte, qui pourrait en outre être compressée différemment ou stockée sur un groupe de fichiers différent.

Et assurez-vous que les développeurs utilisent un littéral au lieu d'un paramètre pour filtrer les lignes IsDeleted. Avec un paramètre, SQL Server doit utiliser le même plan de requête pour les deux cas.

PAR EXEMPLE

SELECT ... WHERE ... AND IsDeleted=0

Et pas:

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

L'utilisation d'un paramètre empêchera l'utilisation de l'index filtré et peut vous causer des problèmes avec le reniflage des paramètres.

13

C'est peut-être une opinion impopulaire, mais je ne pense pas qu'il y ait une réponse "à faire partout"/taille unique à votre question.

Si vous avez des requêtes qui analysent de nombreuses lignes IsDeleted sans raison, une solution consiste à créer un index filtré et non cluster pour satisfaire cette requête.

Une autre option consiste à créer une vue indexée qui pourrait être exploitée par un certain nombre de requêtes différentes, qui est filtrée uniquement sur les lignes non supprimées. Cela pourrait être particulièrement utile sur Enterprise Edition, où la correspondance automatique des vues indexées fonctionne sans fournir un indice NOEXPAND.

Pour les petites tables, ou les tables qui sont lues de façon intensive, l'ajout d'index ou de vues filtrés non clusterisés ou tout autre élément pourrait simplement ajouter une surcharge inutile à votre base de données.

9
Josh Darnell

Dans l'hypothèse raisonnable que les suppressions sont rares, aucune modification des indices n'est une solution appropriée.

J'ai constaté que tôt ou tard, il faut rechercher des références aux lignes supprimées, et les lignes se trouvant dans les index en valent soudainement la peine.

Veuillez noter qu'à moins que vous n'utilisiez des vues, vous devez de toute façon modifier toutes vos requêtes pour inclure les filtres.

2
Joshua

J'espère que vous avez le droit et la possibilité de modifier la requête.

Cependant, puisque chaque jointure/requête devra implémenter la vérification IsDeleted, cela empêcherait-il l'utilisation de l'index filtré (puisque la colonne IsDeleted est utilisée dans la jointure/requête)?

Je voulais dire un point important, j'espère pouvoir l'expliquer.

Dans une requête complexe où Transaction table et Master les deux tables sont utilisées.

Utilisation IsDeleted=0 uniquement dans la table Transaction. Ne pas utiliser dans la table Master.

Exemple,

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

Il ne sert à rien c.isdeleted=0 (à utiliser dans la table Category). Ce n'est pas nécessaire.

De même est-il utile d'utiliser P.isdeleted=0?

Parce que je veux tous les Ordres non supprimés et leurs détails.

Comment Product peut être supprimé lorsque Order est Active ou partout où Productid est référence.

Donc, de cette façon, si vous déboguez soigneusement dans une requête importante, vous pouvez supprimer certains isdeleted = 0.

Ne créez pas aveuglément un index filtré, sélectionnez d'abord toutes ces requêtes très importantes et lentes.

Optimisez ces requêtes lentes, puis décidez uniquement de l'index filtré ou de l'index de réglage.

0
KumarHarsh

J'ai vu un système où le drapeau IS_DELETED est égal à 0 ou à la valeur du PK. Dans d'autres systèmes, c'était le négatif du PK.

Comme la plupart des requêtes ont récupéré des valeurs par la clé "naturelle" ou commerciale (parfois multi-champs), elles n'ont jamais interrogé PK sauf par le biais de jointures; mais ils ont toujours ajouté un AND IS_DELETED = 0 à la fin pour la table principale et pour toutes les tables jointes.

Ce système avait également une table d'audit pour chaque table transactionnelle qui suivait les changements; et l'application avait une fonctionnalité pour afficher toutes les modifications de données, y compris les données supprimées.

0
Rick Ryker