Скорость работы вложенных select'ов

  • Автор темы Автор темы SeaGull
  • Дата начала Дата начала

SeaGull

Junior Member
Скорость работы вложенных select'ов

Обнаружил в притормаживающем скрипте, что запросы типа
select * from TABLE_1 where id in (select id from TABLE_2 where ... )
работают на два порядка дольше, чем если отправить отдельно вложенный запрос, прогнать результаты в PHP и подставить в первый запрос.

Это нормальное явление ?
 
Большое спасибо. Познавательно.

Из ссылки вынес, что это "ненормальное явление", а хорошо известный давний баг с оптимизацией вложенных запросов в MySQL 5.

Жаль.

-~{}~ 11.04.08 16:29:

По ходу подумалось, что раз проблема общая и, наверное, многим как и мне жалко дробить, в ожидании исправления, стройные запросы на составляющие, то может быть в мире уже кто-нибудь озадачивался написанием функции, которая бы делала это автоматически ? Т.е. ты отдаешь функции длинный SQL-запрос, а она находит вложенные запросы, обрабатывает их и подставляет результаты в основной запрос.

Никто такого "патча" не встречал в готовом виде ?
 
SeaGull
замени подзапрос на join, делов то, а то выдумывать какие-то патчи и чтоб наступь на их баги.
 
замени подзапрос на join, делов то
Может, конечно, дело в природной лени и криворукости, на я задолбался править 15-строчные JOIN'ы, подгонять чего в каком порядке поставить, чтобы минимизировать индексы и страдать от некешируемости составляющих этих махин. Хочется комфорту.
 
Может, конечно, дело в природной лени и криворукости, на я задолбался править 15-строчные JOIN'ы, подгонять чего в каком порядке поставить, чтобы минимизировать индексы и страдать от некешируемости составляющих этих махин. Хочется комфорту.
используй SP, Муська> 5.0 это вполне позволяет.
 
SeaGull
sp - stored procedure

Alexandre
не верится, что если загнать один сложный запрос в sp, то будет _значительное_ увеличение производительности. Речь о mysql.
 
Набросал прототип временной "заплатки" для вложенных запросов IN.

Этой функции передается SQL-запрос, а она находит вложенные запросы, обрабатывает их и подставляет результаты в основной запрос. Доведу до ума и буду пользоваться, пока не починят работу индексов во вложенных запросах, чтобы потом не переписывать генераторы запросов.

Функция совершенно сырая, много откровенных дыр (например, если в ключевых полях встречаются круглые скобки);

+ плюсы (побочные эффекты): можно использовать во вложенных запросах LIMIT, чего MySQL 5.0 "doesn't yet support", а также можно использовать вложенные запросы в MySQL младше 5-ой версии.

PHP:
<?

function FindInnerSelect($line)
{
while (eregi("\(select ", $line)):
	$line=preg_replace('~^.+\((select .+)$~iU', '\\1', $line);
	$skobka=1;
	$selector='';
	for ($i=0; $i < strlen($line); $i++):
		if ($line[$i]=='(') {$skobka++;}
		if ($line[$i]==')') {$skobka--;}
		if ($skobka==0) {break;}
		$selector.=$line[$i];
	endfor;
	FindInnerSelect($selector);
endwhile;
return $selector;
}

function MySQL5($query)
{
while (eregi("\(select ", $query)):
	$selector=FindInnerSelect($query);
	$fields=array();
		echo '<b>Executed:</b> '.$selector.'<br>';
	$all=mysql_query($selector);
	if (mysql_num_rows($all)):
		$meta=mysql_fetch_field($all);
		while ($result=mysql_fetch_assoc($all)):
			$fields[]=$meta->numeric?current($result):'"'.addslashes(current($result)).'"';
		endwhile;
	endif;
	$query=str_replace($selector, count($fields)?implode(',', $fields):'null', $query);
endwhile;
return $query;
}

$query='select title from Catalog where uin in (select uin from Sklad where login in (select distinct(login) from Managers)) && grp="sale"';

echo '<b>'.$query.'</b><br><br>';

echo '<br><br><b>'.MySQL5($query).'</b>';

?>

Результат выполнения:

select title from Catalog where uin in (select uin from Sklad where login in (select distinct(login) from Managers)) && grp="sale"

Executed: select distinct(login) from Managers
Executed: select uin from Sklad where login in ("Hindi","SeaGull","Тester1","Tester4")

select title from Catalog where uin in (2020013,2020014,2020017,2020023,2120023,2290552) && grp="sale"
 
Доведу до ума и буду пользоваться, пока не починят работу индексов во вложенных запросах, чтобы потом не переписывать генераторы запросов.
это как голодовка?
 
это как голодовка?
Нет, отнюдь.

На вашей машине обнаруживается прокол колеса и возможности заменить его в ближайшее время нет.
Варианты следующие:
- можно купить проездной и пока поездить на старом, проверенном трамвае.
- можно, хрен с ним, пока ездить и с проколотым колесом.
- можно поставить лысую, штопанную запаску и аккуратно ездить на ней до смены колеса.

Я, соответственно, выбрал последнее.
 
SeaGull
В муське, к сожалению, бывает и так, что тормозит любой запрос с IN (...). Мне недавно встретился такой случай: оказалось быстрее выполнить десяток запросов WHERE id=x, чем 1 запрос WHERE id IN (x1,.., x10). Поскольку id в моем случае - первичный ключ - уж и не знаю, как с этим быть, какие тут индексы к черту могут помочь...

Гугл дал (непроверенную) информацию о том, что, действительно, IN (...) в mysql оптимизируется не очень хорошо.
 
crocodile2u
Гугл дал (непроверенную) информацию о том, что, действительно, IN (...) в mysql оптимизируется не очень хорошо.
Даже если это и так (хотя команда EXPLAIN, по-моему, иного мнения), то всё равно остается дилемма между "оптимизируется не очень хорошо" и "не оптимизируется вобще".
 
Сверху