SQL Server lent sélectionnez à partir de la grande table
J'ai une table avec environ+ de 20 millions de disques.
Structure ressemble à:
EventId UNIQUEIDENTIFIER
SourceUserId UNIQUEIDENTIFIER
DestinationUserId UNIQUEIDENTIFIER
CreatedAt DATETIME
TypeId INT
MetaId INT
Table reçoit environ 100k+ enregistre chaque jour.
J'ai index sur chaque colonne, à l'exception MetaId, comme il n'est pas utilisé dans le " où " clauses
Le problème est quand je veux ramasser par exemple. dernière 100 enregistrements d'SourceUserId
Requête prend parfois jusqu'à 4 minutes à s'exécuter, ce qui n'est pas acceptable.
Par exemple.
SELECT TOP 100 * FROM Events WITH (NOLOCK)
WHERE SourceUserId = '15b534b17-5a5a-415a-9fc0-7565199c3461'
AND
(
TypeId IN (2, 3, 4)
OR
(TypeId = 60 AND SrcMemberId != DstMemberId)
)
ORDER BY CreatedAt DESC
Je ne peux pas faire de partitionnement etc que je suis en utilisant la version Standard de SQL Server et de l'Entreprise est trop cher.
Je pense aussi que le tableau est assez petit pour être que lente.
Je pense que le problème est avec la clause ORDER BY db doit passer par de beaucoup plus grand ensemble de données.
Toutes les idées comment le rendre plus rapide ?
Peut-être relationnel de la base de données n'est pas une bonne idée pour ce genre de données.
De données est toujours en cours ramassé commandé par CreatedAt DESC
Vous remercie pour la lecture.
PabloX
OriginalL'auteur pablox | 2009-12-02
Vous devez vous connecter pour publier un commentaire.
Vous aurez probablement envie de créer un indice composite pour ce type de requête, lorsque la requête s'exécute lentement, il est plus probable que le choix de numériser vers le bas d'un index sur la CreatedAt colonne et d'effectuer un résiduelle du filtre sur la SourceUserId valeur, alors qu'en réalité, ce que vous voulez arriver est de sauter directement à tous les enregistrements pour une SourceUserId commandé correctement - pour ce faire, vous aurez envie de créer un indice composite principalement sur SourceUserId (en effectuant un contrôle d'égalité) et, secondairement, sur CreateAt (afin de préserver l'ordre à l'intérieur d'un SourceUserId valeur). Vous pouvez essayer d'ajouter le TypeId en tant que bien, en fonction de la sélectivité de cette colonne.
Donc, les 2 qui ont le plus de risque de donner le meilleur reproductible de la performance (les essayer et de comparer) serait:
Comme toujours, il y a aussi beaucoup d'autres considérations à prendre en compte dans la détermination de comment/quoi/où à l'index, comme Remus décrit dans une autre réponse, une considération importante est couvrant la requête vs en gardant les recherches. En outre, vous aurez besoin de considérer écrire des volumes, possible la fragmentation de l'impact (le cas échéant), singleton recherches contre les grandes analyses séquentielles, etc., etc.
Le Clustering de cet indice et d'avoir un disque rayé permettrait ainsi.
OriginalL'auteur chadhoc
Non-couvrant les index seront probablement frapper les point tournant et la requête serait de revenir à une analyse de la table. Juste l'ajout d'un index sur chaque colonne, car il est utilisé dans une clause where n'est pas synonyme de bonne conception d'index. Pour prendre votre requête par exemple, un bon de 100% couvrant l'index serait:
Suivant l'indice est utile, bien qu'il va toujours à cause des recherches:
et, enfin, un index w/o tout inclus colonne peut aide, mais il est tout aussi probable sera ignoré (dépend de la colonne des statistiques et des estimations de cardinalité):
Mais un index séparé sur SourceUSerId et un sur CreatedAt est pratiquement inutile pour votre requête.
Voir L'Indice De Conception De Bases.
OriginalL'auteur Remus Rusanu
Le fait que la table des index construit sur des valeurs GUID, indique une possible série de problèmes qui pourraient affecter les performances:
Voici quelques ressources sur la façon d'étudier et de résoudre ces problèmes:
OriginalL'auteur Enrico Campidoglio
Je conseille l'obtention des données à 2 sep var tables
puis appliquer une grande unoin de la sélectionne, ordonné et haut. Limiter les données de l'aller.
OriginalL'auteur Adriaan Stander
Je vous suggère d'utiliser un SYNDICAT:
OriginalL'auteur OMG Ponies
Nous avons réalisé un mineur de gain en passant à un BIGINT IDENTITÉ clé pour notre événement de la table; en utilisant un cluster de clé primaire, on peut tricher et de l'utiliser pour la date de la commande.
OriginalL'auteur Keith Williams
Je m'assurerais CreatedAt est indexé correctement
Order By CreatedAt
clause de!Un index uniquement sur CreatedAt ne serait pas susceptible d'aider à ce type de requête ainsi que d'un composite sur l'égalité filtre SourceUserId - un index uniquement sur CreatedAt permettrait simplement à l'optimiseur de reculer vers le bas d'un B-Arbre en faisant un résiduelle du filtre de vérifier sur le SourceUserId jusqu'à ce qu'il trouve à 100 avec la valeur spécifiée (si le SourceUserId est très sélectif, ce serait probablement une assez longue analyse). Si vous indice composite sur SourceUserId puis CreatedAt, l'optimiseur peut ignorer l'analyse, de chercher à le SourceUserId et tirez tout simplement le pré-commandé finale 100.
OriginalL'auteur Jim B
vous pourriez diviser la question en deux avec une UNION à éviter OU (ce qui peut causer votre index ne pas être utilisé), quelque chose comme
Aussi, vérifiez que le type uniqueidentifier indices ne sont pas REGROUPÉS.
OriginalL'auteur vladhorby
Si il y a 100K enregistrements ajoutés chaque jour, vous devriez vérifier votre indice de fragmentation.
Et de reconstruire ou de les réorganiser en conséquence.
Plus d'infos :
SQLauthority
OriginalL'auteur Leon