Вопрос в следующем: как реализовать "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.
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 написал(а):
Цитата |
Не учи человека плохому, подзапросы это зло. Подзапрос выполняется по одному разу на каждую отобранную в основном запросе строку. ТАк что по сути это те же запросы в цикле. |
я прозрел, спасибо ) осталось только протестировать чей вариант будет скорострельнее...