Je me souviens avoir lu à un moment donné qu'indexer un champ avec une faible cardinalité (un faible nombre de valeurs distinctes) ne valait pas vraiment la peine d'être fait. J'avoue que je ne sais pas assez sur le fonctionnement des index pour comprendre pourquoi.
Alors, que faire si j'ai une table avec 100 millions de lignes et que je sélectionne des enregistrements où un champ de bits est 1? Et disons qu'à tout moment, il n'y a qu'une poignée d'enregistrements où le champ de bits est 1 (par opposition à 0). Vaut-il la peine d'indexer ce champ de bits ou non? Pourquoi?
Bien sûr, je peux simplement le tester et vérifier le plan d'exécution, et je le ferai, mais je suis également curieux de connaître la théorie derrière cela. Quand la cardinalité importe-t-elle et quand ne l'est-elle pas?
la source
Réponses:
Considérez ce qu'est un index en SQL - et l'index est en fait un morceau de mémoire pointant vers d'autres morceaux de mémoire (c'est-à-dire des pointeurs vers des lignes). L'index est divisé en pages afin que des parties de l'index puissent être chargées et déchargées de la mémoire en fonction de l'utilisation.
Lorsque vous demandez un ensemble de lignes, SQL utilise l'index pour trouver les lignes plus rapidement que l'analyse de table (en regardant chaque ligne).
SQL a des index clusterisés et non clusterisés. Ma compréhension des index clusterisés est qu'ils regroupent des valeurs d'index similaires dans la même page. De cette façon, lorsque vous demandez toutes les lignes correspondant à une valeur d'index, SQL peut renvoyer ces lignes à partir d'une page de mémoire en cluster. C'est pourquoi essayer d'indexer une colonne GUID en cluster est une mauvaise idée - vous n'essayez pas de regrouper des valeurs aléatoires.
Lorsque vous indexez une colonne entière, l'index SQL contient un ensemble de lignes pour chaque valeur d'index. Si vous avez une plage de 1 à 10, vous auriez 10 pointeurs d'index. En fonction du nombre de lignes, cela peut être paginé différemment. Si votre requête recherche l'index correspondant à «1» et que le nom contient «Fred» (en supposant que la colonne Nom n'est pas indexée), SQL obtient très rapidement l'ensemble des lignes correspondant à «1», puis la table analyse pour trouver le reste.
Donc, ce que SQL fait vraiment, c'est essayer de réduire l'ensemble de travail (nombre de lignes) sur lequel il doit itérer.
Lorsque vous indexez un champ de bits (ou une plage étroite), vous ne réduisez le jeu de travail que du nombre de lignes correspondant à cette valeur. Si vous avez un petit nombre de lignes correspondantes, cela réduirait considérablement votre jeu de travail. Pour un grand nombre de lignes avec une distribution 50/50, cela peut vous offrir très peu de gain de performances par rapport à la mise à jour de l'index.
La raison pour laquelle tout le monde dit de tester est que SQL contient un optimiseur très intelligent et complexe qui peut ignorer un index s'il décide que l'analyse de table est plus rapide, ou peut utiliser un tri, ou peut organiser les pages de mémoire comme il le souhaite.
la source
Je viens de rencontrer cette question par le biais d'une autre. En supposant que votre déclaration selon laquelle seule une poignée d'enregistrements prend la valeur de 1 (et que ce sont ceux qui vous intéressent), un index filtré pourrait être un bon choix. Quelque chose comme:
Cela créera un index nettement plus petit que l'optimiseur est suffisamment intelligent pour utiliser lorsqu'il s'agit d'un prédicat dans votre requête.
la source
yourBitColumn = @value
, l'optimiseur ne peut pas déterminer si l'index filtré est utilisable.100 millions d'enregistrements avec seulement quelques-uns ayant le champ de bits mis à 1? Oui, je pense que l'indexation du champ de bits accélérerait certainement l'interrogation des enregistrements bit = 1. Vous devriez obtenir le temps de recherche logarithmique à partir de l'index, puis ne toucher que les quelques pages avec des enregistrements bit = 1. Sinon, vous devrez toucher toutes les pages du tableau des 100 millions d'enregistrements.
Là encore, je ne suis certainement pas un expert en bases de données et je pourrais manquer quelque chose d'important.
la source
Si votre distribution est assez connue et déséquilibrée, comme 99% des lignes sont bit = 1 et les 1% sont bit = 0, lorsque vous effectuez une clause WHERE avec bit = 1, une analyse complète de la table sera à peu près au même moment que l'analyse d'index. Si vous voulez avoir une requête rapide où bit = 0, le meilleur moyen que je connaisse est de créer un index filtré, en ajoutant une clause WHERE bit = 0. De cette façon, cet index ne stockera que la ligne 1%. Ensuite, faire un WHERE bit = 0 laissera simplement l'optimiseur de requête choisir cet index, et toutes les lignes de celui-ci seront bit = 0. Vous avez également l'avantage d'avoir une très petite quantité d'espace disque nécessaire pour comparer un index complet sur le bit .
la source
Bien que je ne pense pas que j'indexerais JUSTE une colonne de bits par elle-même, il est très courant d'inclure des colonnes de bits dans le cadre d'un index composé.
Un exemple simple serait un index sur ACTIVE, LASTNAME au lieu de simplement le nom de famille, lorsque votre application recherche presque toujours des clients actifs.
la source
Au cas où vous ne l'auriez pas lu, Jason Massie a récemment écrit un article sur ce sujet.
http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx
Edit: nouvel emplacement de l'article - http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit
Machine de retour pour l'emplacement de l'article précédent "Nouvel": http://web.archive.org/web/20120201122503/http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit/
Le nouvel emplacement de SQL Server Pedia est Toadworld, qui contient un nouvel article de Kenneth Fisher traitant de ce sujet:
http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an-index-on-a-bit-column-will-never-be- used.aspx
machine de retour: http://web.archive.org/web/20150508115802/http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an -index-on-a-bit-column-will-never-be-used.aspx
la source
Bien sûr, cela en vaut la peine, surtout si vous devez récupérer les données par cette valeur. Ce serait similaire à l'utilisation d'une matrice creuse au lieu d'utiliser une matrice normale.
Désormais, avec SQL 2008, vous pouvez utiliser des fonctions de partitionnement et vous pouvez filtrer les données qui vont dans un index. L'inconvénient des versions antérieures serait que l'index serait créé pour toutes les données, mais cela peut être optimisé en stockant les valeurs intéressantes dans un groupe de fichiers séparé.
la source
Comme d'autres l'ont dit, vous voudrez mesurer cela. Je ne me souviens pas où j'ai lu ceci, mais une colonne doit avoir une cardinalité très élevée (environ 95%) pour qu'un index soit efficace. Votre meilleur test pour cela serait de créer l'index et d'examiner les plans d'exécution pour les valeurs 0 et 1 du champ BIT. Si vous voyez une opération de recherche d'index dans le plan d'exécution, vous savez que votre index sera utilisé.
Votre meilleur plan d'action serait de tester le avec une table SELECT * FROM de base WHERE BitField = 1; et développez lentement les fonctionnalités à partir de là, étape par étape, jusqu'à ce que vous ayez une requête réaliste pour votre application, en examinant le plan d'exécution à chaque étape pour vous assurer que la recherche d'index est toujours utilisée. Certes, il n'y a aucune garantie que ce plan d'exécution sera utilisé en production, mais il y a de fortes chances qu'il le soit.
Certaines informations sont disponibles sur les forums sql-server-performance.com et dans l' article référencé
la source
"Je me souviens avoir lu à un moment donné qu'indexer un champ avec une faible cardinalité (un faible nombre de valeurs distinctes) ne valait pas vraiment la peine d'être fait"
En effet, SQL Server trouvera presque toujours qu'il est plus efficace de simplement faire une analyse de table que de lire l'index. Donc, fondamentalement, votre index ne sera jamais utilisé et c'est un gaspillage de le maintenir. Comme d'autres l'ont dit, cela pourrait être correct dans un index composé.
la source
Si votre objectif est de rechercher plus rapidement les enregistrements où la valeur du champ de bits est égale à «1», vous pouvez essayer une vue indexée de votre table de base qui ne contient que les enregistrements où votre champ de bits est égal à «1». Dans l'édition Entreprise, si une requête pouvait utiliser une vue indexée au lieu d'une table spécifiée pour améliorer les performances de la requête, elle utilisera la vue. En théorie, cela augmenterait la vitesse des requêtes de sélection qui ne recherchent que les enregistrements avec une valeur de champ de bits de «1».
http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx
Tout cela suppose que vous êtes Microsoft SQL Server 2005 Enterprise. La même chose pourrait s'appliquer à 2008, je ne connais pas cette version.
la source
Si vous voulez savoir si un index a les effets que vous désirez: testez et testez à nouveau.
En général, vous ne voulez pas d'un index qui ne restreigne pas suffisamment votre table, en raison du coût de maintenance d'un index. (coût> profit). Mais si l'index dans votre cas réduit la table de moitié, vous pouvez gagner quelque chose, mais en le mettant sur la table. Tout dépend de la taille / structure exacte de votre table et de la manière dont vous l'utilisez (nombre de lectures / écritures).
la source
En soi, non car il en résulte très peu de sélectivité. Dans le cadre d'un index composé. très probablement, mais seulement après d'autres colonnes d'égalité.
la source
Vous ne pouvez pas indexer un champ de bits dans SQL Server 2000, comme indiqué dans la documentation en ligne à l'époque:
Oui, si vous n'avez qu'une poignée de lignes, sur des millions, un index vous aidera. Mais si vous voulez le faire dans ce cas, vous devez rendre la colonne a
tinyint
.Remarque : Enterprise Manager ne vous permet pas de créer un index sur une colonne de bits. Si vous le souhaitez, vous pouvez toujours créer manuellement un index sur une colonne de bits:
Mais SQL Server 2000 n'utilisera pas réellement un tel index - exécutant une requête où l'index serait un candidat parfait, par exemple:
SQL Server 2000 effectuera une analyse de table à la place, agissant comme si l'index n'existait même pas. Si vous changez la colonne à un tinyint SQL Server 2000 va faire une recherche d' index. En outre, la requête non couverte suivante:
Il effectuera une recherche d'index, suivie d'une recherche de signet.
SQL Server 2005 a une prise en charge limitée des index sur les colonnes de bits. Par exemple:
provoquera une recherche d'index dans l'index de couverture. Mais le cas non couvert:
ne provoquera pas une recherche d'index suivie d'une recherche de signets, il effectuera une analyse de table (ou une analyse d'index groupé), plutôt que d'effectuer la recherche d'index suivie d'une recherche de signets.
Vérifié par expérimentation et observation directe.
la source
réponse très tardive ...
Oui, cela peut être utile selon l'équipe SQL CAT (mis à jour, a été consolidé)
la source
Est-ce une question courante? Cela peut en valoir la peine lorsque vous recherchez la "poignée" d'enregistrements mais ne vous aidera pas beaucoup sur les autres lignes. Existe-t-il d'autres moyens d'identifier les données?
la source
La cardinalité est un facteur, l'autre est la façon dont l'index divise vos données. Si vous avez environ la moitié des 1 et la moitié des 0, cela vous aidera. (En supposant que cet index est un meilleur chemin à choisir que tout autre index). Cependant, à quelle fréquence insérez-vous et mettez-vous à jour? L'ajout d'index pour les performances SELECT nuit également aux performances INSERT, UPDATE et DELETE, alors gardez cela à l'esprit.
Je dirais que si les 1 à 0 (ou vice versa) ne sont pas meilleurs que 75% à 25%, ne vous inquiétez pas.
la source
mesurer le temps de réponse avant et après et voir s'il en vaut la peine; théoriquement, cela devrait améliorer les performances des requêtes utilisant les champs indexés, mais cela dépend vraiment de la distribution des valeurs vrai / faux et des autres champs impliqués dans les requêtes qui vous préoccupent
la source
Ian Boyd a raison quand il dit que vous ne pouviez pas le faire via Enterprise Manager pour SQL 2000 (voir sa note concernant sa création via T-SQL.
la source
Vous devez être intelligent ici pour interroger, vous devez connaître la valeur de charge sur votre colonne si la charge de true est plus dans votre système et que vous voulez vérifier toutes les vraies valeurs écrivez votre requête pour vérifier non faux .. cela aidera beaucoup , c'est juste un truc.
la source