[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: limit 1 при использовании join
rj45
Вобщем, занялся оптимизацией выборки из таблицы и решил заменить запросы в цикле на один запрос с использованием join.
Вопрос в следующем: как реализовать "LIMIT 1" в приджойненых таблицах?
было:

$firms = array();
$result = mysql_query("select kod, title, date, manager from firms where title like '$l%' and manager=$man order by title");

while ($row = mysql_fetch_array($result)) {

$result1 = mysql_query("select type, date, text from notes where kod=".$row['kod']." order by note_date desc limit 1");
$note = mysql_fetch_array($result1);
$row['note'] = $note;

$result1 = mysql_query("select addr,phones from address where kod=".$row['kod']." limit 1");
$addr = mysql_fetch_array($result1);
$row['addr'] = $addr['addr'];
$row['phones'] = $addr['phones'];

$result1 = mysql_query("select text from position where kod=".$row['kod']." limit 1");
$pos = mysql_fetch_array($result1);
$row['position'] = $pos['text'];

$result1 = mysql_query("select date_c, date_end, date_pay from contract where kod=".$row['kod']." order by date_end desc limit 1");
$contract = mysql_fetch_array($result1);
$row['date_c'] = $contract['date_c'];

// ****************** Определение цвета *******************
$now = time();
if ($contract['date_pay']) {
if ($now < strtotime($contract['date_end'])) {
$row['color'] = '#c6df9c';
} else {
$row['color'] = '#f7977a';
}
}
else {
$row['color'] = '#cccccc';
}
// ********************************************************
$firms[] = $row;
}
return $firms;

Хочу привести эту кучу запросов (после первого в некоторых моментов выходит порялка 5000 результатов и потом порядка 5000*3 дополнительных запросов в цикле) к одному вида:

select
firms.kod, firms.title, firms.date, firms.manager, notes.type, notes.date as noteDate,
address.addr, address.phones, contract.date_c, contract.date_end, contract.date_pay
from
firms left join address on (address.kod=firms.kod) left join notes on (notes.kod=firms.kod)
left join position on (position.kod=firms.kod) left join contract on (contract.kod=firms.kod)
where
firms.title like '%А' and firms.manager=30 order by firms.title

Блок *определение цвета* реализую потом при выводе.



Спустя 10 минут, 55 секунд (20.06.2012 - 12:07) varvar написал(а):
kod - это primary key? лимит тогда там вобще не нужен

Спустя 10 минут, 2 секунды (20.06.2012 - 12:17) vagrand написал(а):
Приведенный вами результирующий запрос очень не оптимален сам по себе:
1. firms.title like '%А' - тут уже 100% ключи использоваться не будут;
2. left join - это плохо, лучше inner join.

Спустя 41 секунда (20.06.2012 - 12:18) rj45 написал(а):
Цитата
kod - это primary key? лимит тогда там вобще не нужен

в таблице firms - да primary, в notes - просто поле без индекса, в address - просто индекс, position - тоже просто индекс.

При выполнении запросов в цикле результат - 24 строки
При выполнении одним запросом (как указано в первом посте в конце) - 299. Это потому что, для одной фирмы (например, kod=1234) есть несколько адресов (уже 2 строки), а нужно выбрать только первый. То же с notes, position и contract

И еще одно забыл - кроме limit 1 нужно еще и order_by для приджойненых таблиц

Спустя 3 минуты, 36 секунд (20.06.2012 - 12:21) rj45 написал(а):
Цитата
1. firms.title like '%А' - тут уже 100% ключи использоваться не будут;
2. left join - это плохо, лучше inner join.

А как лучше, если нужно выбрать фирмы, тайтл которых начинается на "А" ?
left join потому, что есть фирмы, для которых адрес не задан вообще и тогда inner join вообще эту фирму не выберет, а left join дополнит отсутствующие поля значением NULL. Или я не правильно понял мануалы?

Спустя 15 минут, 44 секунды (20.06.2012 - 12:37) varvar написал(а):
может так прокатит... чет сам в твоем запросе уже заблудился

$query="SELECT `f`.`kod`, `f`.`title`, `n`.`date`, `p`.`manager` FROM `firms` `f`
INNER JOIN (SELECT `type`, `date`, `text` FROM `notes` WHERE `kod`="
.$row['kod']." ORDER BY `note_date` DESC LIMIT 1) `n` ON `f`.`kod`=`n`.`kod`
INNER JOIN (SELECT `addr`,`phones` FROM `address` WHERE `kod`="
.$row['kod']." LIMIT 1) `a` ON `f`.`kod`=`a`.`kod`
INNER JOIN (SELECT `text` FROM `position` WHERE `kod`="
.$row['kod']." LIMIT 1) `p` ON `f`.`kod`=`p`.`kod`
WHERE `f`.`title` LIKE '
$l%' AND `p`.`manager`=$man
ORDER BY `f`.`title`";

Спустя 55 минут, 11 секунд (20.06.2012 - 13:32) vagrand написал(а):
Цитата
в notes - просто поле без индекса


Очень плохо, если по полю идет join то индекс для него нужен, не обязательно примари но нужен.

Цитата
А как лучше, если нужно выбрать фирмы, тайтл которых начинается на "А" ?


Если надо выбирать тайтл который на A начинается то надо писать так "А%", а лучше всего сделать отдельное поле в котором хранить первые буквы фирм и искать уже по нему, естественно с ключем.

Цитата
left join потому, что есть фирмы, для которых адрес не задан вообще и тогда inner join вообще эту фирму не выберет, а left join дополнит отсутствующие поля значением NULL. Или я не правильно понял мануалы?


Правильно поняли, но left join намного медленнее чем inner.

varvar
Цитата
может так прокатит...

Не учи человека плохому, подзапросы это зло. Подзапрос выполняется по одному разу на каждую отобранную в основном запросе строку. ТАк что по сути это те же запросы в цикле.

rj45
Я вижу для вас только один нормальный вариант:
1. Собрать все id кодов из первого запроса в массив;
2. Выполнить остальные запросы по одному разу ри помощи условия: kod in (...);
3. При выводе собрать все воедино

Спустя 1 час, 58 минут, 6 секунд (20.06.2012 - 15:30) varvar написал(а):
Цитата

Не учи человека плохому, подзапросы это зло. Подзапрос выполняется по одному разу на каждую отобранную в основном запросе строку. ТАк что по сути это те же запросы в цикле.


я прозрел, спасибо ) осталось только протестировать чей вариант будет скорострельнее...
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.