web-dev-qa-db-fra.com

Optimisation des performances PL/SQL pour LIKE '% ...%' Requêtes génériques

Nous utilisons la base de données Oracle 11g.
Comme vous le savez peut-être ou non, si vous utilisez une requête générique avec "%" devant la chaîne, la colonne index n'est pas utiliséet un analyse complète du tableauest en cours) .

Il semble qu'il n'y ait pas de suggestion définitive sur la manière d'améliorer ce type de requête, mais vous pourriez peut-être partager des informations précieuses tirées de votre expérience sur la manière d'optimiser la requête suivante:

SELECT * 
  FROM myTable 
 WHERE UPPER(CustomerName) like '%ABC%' 
    OR UPPER(IndemnifierOneName) like '%ABC%' 
    OR UPPER(IndemnifierTwoName) like '%ABC%';

... où les 3 colonnes sont de type varchar2 (100)et ABCest une valeur de paramètre d'entrée variable.

@Tous suggéronsCONTEXindex, veuillez noter que mes données sont mises à jour à tout moment de la journée et que cet index nécessite une resynchronisation, d'où pasune bonne option pour une table de 1,5 million de lignes, désolé.

P.S. Je vais upvoter chaque réponse, alors s'il vous plaît, continuez.

15
Tsar

Comme déjà mentionné, vous pouvez ajouter un index de contexte ctx aux colonnes de noms.

en supposant qu'un petit nombre d'enregistrements soient mis à jour, une option consiste à actualiser votre index quotidiennement. (et enregistrez quand c'est arrivé)

ajoutez ensuite une colonne et un index de date lastupdate à la table dans laquelle vous effectuez la recherche.

Il devrait être possible d’analyser votre index ctx pour la plupart des anciennes données non modifiées et de sélectionner un faible pourcentage de données mises à jour à l’aide de la méthode traditionnelle LIKE, par exemple:

WHERE (lastupdated<lastrefresh AND contains(name,'%ABC%')) 
   OR (lastupdated>lastrefresh AND name like '%ABC%')

REMARQUE: vous pouvez trouver que votre plan de requête est un peu mental (beaucoup de conversions bitmap en identificateurs de ligne), dans ce cas, divisez les 2 parties du OR en une requête UNION ALL. par exemple

SELECT id FROM mytable   
    WHERE 
    (lastupdate>lastrefresh and name LIKE '%ABC%')
    UNION ALL
    SELECT id FROM mytable   
    WHERE lastupdate<lastrefresh and CONTAINS(name, '%ABC%', 1) > 0
6
Kevin Burton

La seule optimisation consiste à ne pas utiliser ce type de requête, mais plutôt à utiliser les fonctionnalités natives de la plateforme de base de données:

Voir le texte Oracle: http://www.Oracle.com/technetwork/database/enterprise-edition/index-098492.html

La réponse commune aux questions relatives à SQL Server serait la recherche en texte intégral. Il est agréable de voir qu'Oracle a quelque chose d'aussi bon ou de meilleur.

6
Fosco

La UPPER() tue vos index avant tout, envisagez d'utiliser une expression rationnelle. Le % initial peut éviter une analyse d'index normale, mais n'aboutit pas toujours à une analyse complète de la table mais à une analyse complète de l'index, qui est plus rapide que FTS.

Je suppose que 'ABC' est variable. Sinon, un index de fonction est la voie à suivre.

2
Samuel

Parfois, ce type de requête est inévitable - extraire le domaine à partir d'une URL, ou peut-être la racine d'un mot avec un préfixe et un suffixe.

Vous pouvez recourir à un index de texte intégral avec ou sans tokenizer personnalisé.

Si les chaînes recherchées sont finies et connues à l’avance (par exemple, vous travaillez avec un ensemble limité de noms de domaine devant être extraits d’une URL), vous pouvez utiliser une fonction déterministe pouvant être indexée.

http://www.akadia.com/services/ora_function_based_index_2.html

0
Tim