2011-11-04 3 views
1

De travailler sur cette situation spécifique, il était de nouvelles à moi que les opérateurs logiques ne sont pas court-circuités en SQL.SQL 2008: Empêcher la recherche de texte intégral dans la requête quand elle n'est pas nécessaire

je fais régulièrement quelque chose dans ce sens dans la clause where (généralement lorsque le traitement des requêtes de recherche):

WHERE 
    (@Description IS NULL OR @Description = myTable.Description) 

qui, même si ce n'est pas court-circuité dans cet exemple, ne pas vraiment d'importance. Cependant, quand il s'agit des fonctions de recherche fulltext, cela importe. Si la deuxième partie de cette requête était CONTAINS(myTable.Description, @Description), cela ne fonctionnerait pas car la variable n'est pas autorisée à être nulle ou vide pour ces fonctions.

Je trouve les WHEN déclarations de CASE sont exécutées dans l'ordre, donc je peux changer ma requête comme si pour assurer la recherche de texte intégral est appelé uniquement en cas de besoin, ainsi changeant la variable de zéro à '""' quand il est nul à permettre à la requête à exécuter:

WHERE 
    (CASE WHEN @Description = '""' THEN 1 WHEN CONTAINS(myTable.Description, @Description) THEN 1 ELSE 0 END = 1) 

le code ci-dessus doit empêcher la pièce de requête de texte intégral de l'exécution moins qu'il y ait effectivement une valeur à rechercher avec. Ma question est, si j'exécute cette requête où @Description est '""', il reste encore un peu de temps dans le plan d'exécution passé à traiter les recherches d'index en cluster et fulltextmatch, même si cette table et cette recherche ne se terminent pas être utilisé du tout: existe-t-il un moyen d'éviter cela? J'essaie de sortir ceci d'une requête dynamique codée en dur et dans une procédure stockée, mais si la procédure finit par être plus lente, je ne suis pas sûr que je peux le justifier.

Répondre

0

Au cas où quelqu'un d'autre rencontrerait un scénario comme celui-ci, c'est ce que j'ai fini par faire, ce qui est assez proche de ce que M_M voulait dire; Je me suis cassé loin les morceaux de texte intégral et les a placés derrière les branches:

DECLARE @TableBfullSearch TABLE (TableAId int) 
IF(@TableBSearchInfo IS NOT NULL) 
    INSERT INTO @TableBfullSearch 
    SELECT 
     TableAId 
    FROM 
     TableB 
    WHERE 
    ...(fulltext search)... 

DECLARE @TableCfullSearch TABLE (TableAId int) 
IF(@TableCSearchInfo IS NOT NULL) 
    INSERT INTO @TableCfullSearch 
    SELECT 
     TableAId 
    FROM 
     TableC 
    WHERE 
    ...(fulltext search)... 

--main query with this addition in the where clause 
SELECT 
    ... 
FROM 
    TableA 
WHERE 
    ... 
    AND (@TableBSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM @TableBfullSearch)) 
    AND (@TableCSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM @TableCfullSearch)) 

Je pense que c'est probablement à peu près aussi bon que ça va arriver sans une sorte de requête dynamique

0

Ce n'est pas idéal, mais peut-être quelque chose comme ça fonctionnerait:

IF @Description = '' 
BEGIN 
    SELECT ... 
END 
ELSE 
BEGIN 
    SELECT ... 
    WHERE CONTAINS(mytable.description, @Description) 
END 

De cette façon, vous évitez mysql et en cours d'exécution aussi l'analyse FT quand il est pas nécessaire.

En général, je trouve que CONTAINSTABLE est un peu plus rapide. En outre, puisque le plan de requête va être très différent que vous utilisiez ma solution ou la vôtre, faites attention à parameter sniffing. Le reniflage de paramètre est lorsque l'optimiseur construit un plan basé sur une valeur de paramètre spécifique transmise.

+0

Ça va être un peu casse-gueule, car il y a 2 de ces recherches facultatives dans la requête, donc je me retrouverais avec 4 branches – John

Questions connexes