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

SeaGull

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

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

Это нормальное явление ?
 

SeaGull

Junior Member
Большое спасибо. Познавательно.

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

Жаль.

-~{}~ 11.04.08 16:29:

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

Никто такого "патча" не встречал в готовом виде ?
 

Gas

может по одной?
SeaGull
замени подзапрос на join, делов то, а то выдумывать какие-то патчи и чтоб наступь на их баги.
 

SeaGull

Junior Member
замени подзапрос на join, делов то
Может, конечно, дело в природной лени и криворукости, на я задолбался править 15-строчные JOIN'ы, подгонять чего в каком порядке поставить, чтобы минимизировать индексы и страдать от некешируемости составляющих этих махин. Хочется комфорту.
 

Alexandre

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

Gas

может по одной?
SeaGull
sp - stored procedure

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

SeaGull

Junior Member
Набросал прототип временной "заплатки" для вложенных запросов 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"
 

Wicked

Новичок
Доведу до ума и буду пользоваться, пока не починят работу индексов во вложенных запросах, чтобы потом не переписывать генераторы запросов.
это как голодовка?
 

SeaGull

Junior Member
это как голодовка?
Нет, отнюдь.

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

Я, соответственно, выбрал последнее.
 

crocodile2u

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

Гугл дал (непроверенную) информацию о том, что, действительно, IN (...) в mysql оптимизируется не очень хорошо.
 

SeaGull

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