MySQL « как реализовать быстрый поиск по множеству условий (в частности тегов)?

Есть три таблицы articles, tags, tagging

Классическая схема.

Но как искать по множеству условий тегов именно ту статью которую нужно?

например, юзер вводит несколько тегов, и появляются такие результаты поиска где

присутствуют все данные теги, я так понимаю здесь много вложенные запросов должно быть?

Вот например, такой запрос работать не будет, такой запрос только с OR будет работать.

Мне надо чтобы получился результат такой же как если бы тут работало с AND.

/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.geshi_code {font-family:monospace;} .php.geshi_code .imp {font-weight: bold; color: red;} .php.geshi_code .kw1 {color: #b1b100;} .php.geshi_code .kw2 {color: #000000; font-weight: bold;} .php.geshi_code .kw3 {color: #990000;} .php.geshi_code .co1 {color: #666666; font-style: italic;} .php.geshi_code .co2 {color: #666666; font-style: italic;} .php.geshi_code .co3 {color: #0000cc; font-style: italic;} .php.geshi_code .co4 {color: #009933; font-style: italic;} .php.geshi_code .coMULTI {color: #666666; font-style: italic;} .php.geshi_code .es0 {color: #000099; font-weight: bold;} .php.geshi_code .es1 {color: #000099; font-weight: bold;} .php.geshi_code .es2 {color: #660099; font-weight: bold;} .php.geshi_code .es3 {color: #660099; font-weight: bold;} .php.geshi_code .es4 {color: #006699; font-weight: bold;} .php.geshi_code .es5 {color: #006699; font-weight: bold; font-style: italic;} .php.geshi_code .es6 {color: #009933; font-weight: bold;} .php.geshi_code .es_h {color: #000099; font-weight: bold;} .php.geshi_code .br0 {color: #009900;} .php.geshi_code .sy0 {color: #339933;} .php.geshi_code .sy1 {color: #000000; font-weight: bold;} .php.geshi_code .st0 {color: #0000ff;} .php.geshi_code .st_h {color: #0000ff;} .php.geshi_code .nu0 {color: #cc66cc;} .php.geshi_code .nu8 {color: #208080;} .php.geshi_code .nu12 {color: #208080;} .php.geshi_code .nu19 {color:#800080;} .php.geshi_code .me1 {color: #004000;} .php.geshi_code .me2 {color: #004000;} .php.geshi_code .re0 {color: #000088;} .php.geshi_code span.xtra { display:block; }


   //$tag_ar - обработанный массив содержащий все условия которые ввел юзер
   $query = "SELECT articles.id,  articles.title, ";
    $query .= "articles.sh_description ";
    $query .= "FROM articles, tagging WHERE ((tagging.tag = '";
    $query .= implode("') AND (", $tag_ar);
    $query .= "')) AND tagging.article_id = articles.id";

 


И притом может быть можно сделать чтобы после того я юзер произвел поиск по одному условию это кешировалось, например, и когда мы получаем 2-ое условие искало бы в уже найденном.

Хотя скорость доступа к файловой системе медленнее чем к базе данных.

В общем подскажите самый быстрый запрос, который тут можно сооружать динамически, ну и как работу этого всего можно оптимизировать по максимуму. Спасибо.
--------------------------------------------------
Благодарю за ответ, просто в моей практике не требовались вложенные запросы обычно.

Теперь буду изучать их дальше. Только вот думаю такой запрос довольно ресурсоемкий, как бы минимизировать нагрузку, если допустим накопится 1 000 000 или больше записей в базе данных.

1 ответов




  $num_tags = count($tag_arr);
  $tag_str = "'".implode("', ", $tag_ar)."'";
   
  $query = "SELECT articles.id,  articles.title, articles.sh_description
  FROM articles
  INNER JOIN tagging ON (tagging.article_id = articles.id)
  WHERE tagging.tag  IN ("
. $tag_str .")
  GROUP BY articles.id
  HAVING COUNT(DISTINCT tagging.tag) =."
.$num_tags;
 
* $tag_ar должен хранить уникальные тэги.

Если элементы в массиве $tag_ar приходят от пользователя, то для предотвращения sql injection надо еще каждый элемент обработать mysql_real_escape_string , например так

  $tag_str = "";
  foreach ($tag_ar as $val)
  {    
     $tag_str .= "'".mysql_real_escape_string($val)."',";        
  }
  $tag_str = substr($tag_str, 0, -1);