2013-02-19 4 views
0

Я немного искал что-то, чтобы оптимизировать следующие вложенные запросы while(), но, к сожалению, я не могу его адаптировать для своего случая.Как оптимизировать SQL-запрос, чтобы избежать() вложенных подзапросов?

Давайте представим следующие отношения к базе данных:

ITEM 0,5---1,n ITEM_TAG 1,n---0,n TAG 

ITEM (id, name, ...) 
ITEM_TAG (id_item, id_tag) 
TAG (id, name, ...) 

Теперь мы хотим, чтобы все элементы с их СТП (ограниченные по 5).

Что я сделал это некрасиво следующий которым должен быть оптимизировано:

$req=mysql_query("SELECT id, name FROM ITEM WHERE 1 ORDER BY id DESC"); 
while($res=mysql_fetch_array($req)) 
{ 
    $items.="<h1>".$res['name']."</h1>"; 
    $req_tag=mysql_query("SELECT id, name 
         FROM TAG, ITEM_TAG 
         WHERE ITEM_TAG.id_item='".$res['id']."' 
         AND ITEM_TAG.id_tag=TAG.id 
         LIMIT 5"); 
    while($res_tag=mysql_fetch_array($req_tag)) 
    $items.="&bull; ".$res_tag['name']."<br/>"; 
} 

Другим способом может быть, чтобы выбрать все элементы и их тег и фильтровать их с массивом, как следующее:

$req=mysql_query("SELECT ITEM.id AS 'item_id', 
         ITEM.name AS 'item_name', 
         TAG.id AS 'tag_id', 
         TAG.name AS 'tag_name' 
         FROM ITEM, ITEM_TAG, TAG 
         WHERE ITEM_TAG.id_item=ITEM.id 
         AND ITEM_TAG.id_tag=TAG.id 
         ORDER BY ITEM.id DESC"); 
    while($res=mysql_fetch_array($req)) 
    { 
    $listTag[$res['item_id']][$res['tag_id']]=$res['tag_name']; 
    $listItem[$res['item_id']]=$res['item_name']; 
    } 
    foreach($listItem as $item_id=>$item_name) 
    { 
    $items.="<h1>".$val."</h1>"; 
    foreach($listTag[$id_item] $tag_id=>$tag_name) 
    $items.="&bull; ".$tag_name."<br/>"; 
    } 

Любая идея или совет, чтобы сделать это лучше, быстрее, легче (и не сильнее, как Daft punk;))?

LEFT JOIN, RIGHT JOIN или поместить tag1, tag2 ... tag5 в таблицу ITEM или другую? Но обратите внимание, что ITEM могут иметь от 0 до 5 TAG, связанных ...

+0

Я немного колебался, когда говорил о получении результатов из БД и кешировании их в PHP перед выходом; но вы можете попробовать свой текущий подход с помощью MySQLi/PDO и подготовленного оператора, поэтому вам нужно только один раз подготовить «SELECT id, name FROM tag ...» и иметь относительно быструю производительность без восстановления вашей логики. – Passerby

+0

Спасибо за ваш ответ, но я думаю, что цикл запроса будет таким же? даже с некоторыми MySQLi или PDO, doctrine ... – Valky

+0

Вам понадобятся два оператора: '$ item = $ mysqli-> prepare (" SELECT id FROM item ... "); $ tag = $ mysqli-> prepare (" SELECT name FROM tag ... WHERE id_item =? ")'. Вам все равно нужно выполнить внутренний цикл '$ tag', но' $ tag' был подготовлен, поэтому в базу данных он отличается от прямого 'mysql_query' и, следовательно, лучшей производительности. – Passerby

ответ

1

Это слишком длинное для этого в комментариях, поэтому я публикую здесь.

Говоря о кэшировании результатов DB в PHP перед выходом, я всегда буду немного замялся, так как это не «интуитивно понятное» для отношения * данных * базы и PHP.

В этом случае, особенно если у вас есть очень большая таблица ITEM, вы будете кэшировать много строк в PHP, прежде чем сможете их вывести.

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

$req=$mysqli->query("SELECT id, name FROM ITEM WHERE 1 ORDER BY id DESC"); 
$tag=$mysqli->prepare("SELECT id, name FROM tag, item_tag WHERE item_tag.id_item=? AND item_tag.id_tag=tag.id LIMIT 5"); 
$tag->bind_param("i",$tid); 
while($res=$req->fetch_assoc()) 
{ 
    echo "<h1>".$res['name']."</h1>"; 
    $tid=intval($res["id"]); 
    $tag->execute(); 
    $req_tag=$tag->get_result(); 
    while($res_tag=$req_tag->fetch_assoc()) 
    { 
    echo "&bull; ".$res_tag['name']."<br/>"; 
    } 
} 

Приведенный выше код не тестировался, но я думаю, что вы можете получить эту идею.

+0

Большое спасибо, кажется, интересно, даже если я думаю (я не знаю, почему LOL), запрос будет выполнен в цикле. Собираюсь попробовать это, и я скажу вам. +1 в любом случае. – Valky

+0

@Valky В цикле запрос действительно выполняется, но есть существенные отличия (особенно если у вас большая таблица 'ITEM') с' mysql_query', что 'mysqli' продолжает выполнять один и тот же запрос с разными , а mysql всегда предлагает новый запрос. – Passerby

 Смежные вопросы

  • Нет связанных вопросов^_^