2016-03-08 4 views
2

Scénario (j'ai essayé de trouver un mappage 1-1 dans mon scénario de production): Récupérer la liste de toutes les personnes qui ont voyagé avec Virgin Airlines ou Emirates depuis New York.Pourquoi la requête SQL n'utilise-t-elle pas la clé primaire pour SELECT lorsqu'elle est la plus appropriée?

Le tableau: tbl_Flyer contient quelques colonnes contenant tous les détails sur les personnes qui ont volé à n'importe quel moment. La clé primaire est CountryId, CityId, AirlineId, PersonId

Maintenant, une simple requête SQL ressemble à ceci:

SELECT flyer.PersonId 
FROM tbl_Flyer passenger 
WHERE passenger.CountryId = @countryId 
     AND passenger.City= @cityId 
     AND passenger.AirlineId IN (SELECT values FROM @allAirlineIds) 

@countryId et @cityId et @allAirlineIds sont correctement envoyés à la procédure stockée SQL. Mon hypothèse serait que cette requête utiliserait la clé primaire car toutes les 4 colonnes utilisées dans la requête sont présentes dans PK, mais pour une raison quelconque, ce n'est pas le cas.

Il utilise un index non cluster qui a été ajouté pour pouvoir interroger les passagers sur la base de détails personnels tels que l'âge, le sexe. (ressemble (CountryId, CityId, âge, sexe))

J'ajoute un indice ForceSeek à la requête mais je veux comprendre s'il y a un anti-pattern que je pourrais utiliser ici? N'importe quelle idée pourquoi SQL défierait la logique et n'utiliserait pas le PK pour une recherche?

+2

Vous devriez évitez de construire une telle clé primaire compliquée. Faites une identité-colonne de substitution la clé primaire et ajoutez une contrainte unique pour toute combinaison de colonnes souhaitée. Et je suggère de toujours utiliser 'exists' au lieu de' dans (select ... '. –

+0

la clé primaire m'aide à partitionner les données dans la base de données, je n'ai pas d'autres options simples pour partitionner les données en fonction de – divyanshm

+0

Vous ne savez pas si le partitionnement par pays a un effet sur les données de vol, mais vous avez probablement une meilleure compréhension: s'agit-il d'un véritable partitionnement ou simplement d'un index clusterisé qui influence l'ordre physique des lignes? –

Répondre

0

Le choix par votre moteur de base de données d'utiliser un index ou un autre est fait automatiquement sur la base d'heuristiques automatiques ... qui ne sont pas toujours les plus précises. (99% des fois, ils sont, mais parfois, le cerveau humain a trouvé un meilleur moyen). Ces heuristiques sont calculées sur la base de règles généralistes, et parfois ne correspondent pas à la réalité du contenu de votre base de données (colonne colonne avec toujours la même première lettre, colonne avec beaucoup de null, ...)

L'opération "Sélectionner dans" doit être effectuée pour chaque ligne de votre table, stockée et considérée comme extrêmement chère par la plupart des moteurs de base de données, de sorte que votre base de données peut utiliser d'une autre manière. En utilisant Exist in est considéré comme beaucoup moins cher, et rendra votre moteur de base de données plus susceptible de choisir l'index. Utilisez ForceSeek si ce n'est pas assez.

Vous pouvez aussi avoir le même problème si le type de CountryId, CityID, AirlineId, personID est pas la même que @CountryId, @CityId, @AirlineId, @PersonId (la conversion de type est cher)