Si Apps.mfrId est nul, vous rejoignez tous les fabricants.
De vos tests, "OU ISNULL (apps.mfrId, 0) = 0" le fait moins cher que "OU Apps.mfrId IS NULL OU Apps.mfrId = 0"
Ces paraient assez équivalent, et vous avez déjà une solution, alors la question est de savoir pourquoi et/ou comment faire fonctionner le non-performer.
En ce qui concerne ces performances, si tout ce que vous dites est exact, comme nous commençons à demander pourquoi, nous commençons à pointer vers le Optimiseur de requête. S'il fonctionne différemment pour les mêmes paramètres, il aura un plan de requête différent. Vous verrez probablement une analyse de table au lieu de l'utilisation de l'index, ou une autre explication à la mauvaise performance.
Je vous encourage à comparer les plans de requête, ou d'amener quelqu'un d'autre à, pour aider à apporter une réponse à ce qu'il fait différemment. Mais, vous pouvez déjà dire qu'il fait quelque chose différemment.
Une possibilité est que lorsque Optimiseur de requête fixe sont libérés, ils par défaut ne sont pas activés, sauf si drapeau 4199 (pour tous les correctifs ou d'autres indicateurs pour des corrections spécifiques) sont activés. En effet, une correction générale peut être bonne pour la plupart, mais peut également casser une application qui a été optimisée dans l'environnement d'exister les problèmes antérieurs.
https://dba.stackexchange.com/questions/102292/trace-flag-4199-enable-globally
Ne tournant 4199 sur l'aide?
select top 2000 Apps.object_id
from
Manufacturer
INNER JOIN Apps ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0
)
where
Apps.OBJECT_ID = 6879149
OPTION(QUERYTRACEON 4199)
Un autre sujet lié est paramètre renifler. Parfois, un plan de requête peut être mis en cache qui est optimal pour un paramètre mais horrible pour un autre paramètre.Dans votre cas, une application peut renvoyer un fabricant, mais une autre application peut renvoyer tous les fabricants, ce qui explique pourquoi cela vaut la peine d'être mentionné. Cela se manifeste généralement par le fait que le même code fonctionne de manière incohérente lorsque les paramètres sont différents. Vous pouvez essayer de désactiver le reniflage des paramètres ou de forcer la recompilation pour aider à diagnostiquer si cela semble faire partie du problème.
What are the main differences between OPTION(OPTIMIZE FOR UNKNOWN) and OPTION(RECOMPILE)?
J'ai vu des situations où se sentaient comme l'optimisateur de requêtes avaient abandonné sur les indices lisant attentivement, juste parce que la déclaration est devenu trop complexe. Mais cela ne semble pas probable dans votre exemple; Les bogues de l'optimiseur de requêtes sont corrigés, mais pour les utiliser, vous devez toujours activer les indicateurs de requête, sinon le correctif que vous installez peut très bien ne rien faire. Parfois, vous pouvez également essayer de guider l'optimiseur sql. S'il existe un index qui devrait toujours être utilisé, cela peut être donné comme un indice de requête.
Je serais également curieux de savoir si ce qui suit supprime la question:
select top 2000 Apps.object_id
from
(
select Apps.object_id, Apps.mfrId
from Apps
where Apps.OBJECT_ID = 6879149
) Apps
left join Manufacturer ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0)
Si tous les correctifs de l'optimiseur de requêtes sont activés, et le problème persiste, il faut se demander pourquoi l'optimiseur de requêtes a ce. Il ne peut utiliser que des index existants et il peut seulement déterminer si l'utilisation d'un index sera bénéfique si des statistiques existent. Pendant ce temps, des statistiques obsolètes conduiront à de mauvais choix. Il peut être bon de reconstruire/réorganiser les index et mettre à jour les statistiques périodiquement. Vous pouvez essayer de le faire et voir si cela a un effet.
Conclusion
Puisque vous avez déjà une solution de travail, ne l'utiliser. Mais votre question est de savoir pourquoi deux choses très similaires obtiennent des résultats très différents. En supposant que le même paramètre est utilisé, et en tenant compte du fait que vos deux options sont si similaires, le problème pointe vers un mauvais choix de l'optimiseur de requête. Cela suggère que vous devrez peut-être à la fois installer les derniers correctifs (s'ils ne sont pas installés) et activer 4199 pour activer tous les correctifs de l'optimiseur de requêtes que vous avez déjà installés via les correctifs de serveur SQL. Cela inclut l'ajout d'OPTION (QUERYTRACEON 4199) au bas de votre SQL ou l'activation de 4199 globalement ou similaire.
Avez-vous montré le plan d'exécution pour chaque requête? –
cette condition de jointure semble terriblement étrange. Est-ce une jointure gauche, une jointure interne, ???? Je suis intéressé par pourquoi vous voudriez une condition de jointure qui serait surchargée si le apps.mfrid était nul. On dirait que vous voulez simplement une jointure complète. Quel est l'objectif final? – scsimon
@scsimon C'est une jointure interne. Je travaille avec des tables que je n'ai pas conçues. Apps.mfrId est une clé étrangère nullable à Manufacturer.id (sans configuration de contraintes de clé étrangère). Pour une raison quelconque, la conception d'origine autorise NULL ou 0, et NULL ou 0 ont la même signification (aucune valeur valide n'est définie). –