<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>kocherov.net &#187; sql</title>
	<atom:link href="https://kocherov.net/tag/sql/feed/" rel="self" type="application/rss+xml" />
	<link>https://kocherov.net</link>
	<description>создание и поддержка парсеров, систем сбора и анализа информации</description>
	<lastBuildDate>Thu, 19 Feb 2026 13:03:25 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6.1</generator>
		<item>
		<title>truncate all tables mysql</title>
		<link>https://kocherov.net/truncate-al-tables-mysql/</link>
		<comments>https://kocherov.net/truncate-al-tables-mysql/#comments</comments>
		<pubDate>Sun, 27 Mar 2016 09:09:13 +0000</pubDate>
		<dc:creator>Pavel Kocherov</dc:creator>
				<category><![CDATA[Работа]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://kocherov.net/?p=780</guid>
		<description><![CDATA[Как быстро очистить все таблицы в базе? SELECT Concat('TRUNCATE TABLE ',table_schema,'.',TABLE_NAME, ';') FROM INFORMATION_SCHEMA.TABLES where table_schema in ('db1_name','db2_name'); Выполните этот запрос и получите список запросов для очистки каждой таблицы. Далее просто скопируйте его и выполните.]]></description>
				<content:encoded><![CDATA[<p>Как быстро очистить все таблицы в базе?</p>
<pre><code>SELECT Concat('TRUNCATE TABLE ',table_schema,'.',TABLE_NAME, ';') 
FROM INFORMATION_SCHEMA.TABLES where  table_schema in ('db1_name','db2_name');</code></pre>
<p>Выполните этот запрос и получите список запросов для очистки каждой таблицы. Далее просто скопируйте его и выполните.</p>
]]></content:encoded>
			<wfw:commentRss>https://kocherov.net/truncate-al-tables-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Чем HAVING отличается от WHERE</title>
		<link>https://kocherov.net/chem-having-otlichaetsya-ot-where/</link>
		<comments>https://kocherov.net/chem-having-otlichaetsya-ot-where/#comments</comments>
		<pubDate>Wed, 05 Feb 2014 08:19:46 +0000</pubDate>
		<dc:creator>Pavel Kocherov</dc:creator>
				<category><![CDATA[Работа]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://kocherov.net/?p=411</guid>
		<description><![CDATA[При помощи HAVING отражаются все предварительно сгруппированные посредством GROUP BY блоки данных, удовлетворяющие заданным в HAVING условиям. Это дополнительная возможность “профильтровать” выходной набор. Условия в HAVING отличаются от условий в WHERE: HAVING исключает из результирующего набора данных группы с результатами агрегированных значений; WHERE исключает из расчета агрегатных значений по группировке записи, не удовлетворяющие условию; в условии поиска WHERE нельзя задавать агрегатные функции.]]></description>
				<content:encoded><![CDATA[<p>При помощи <code>HAVING</code> отражаются все предварительно сгруппированные посредством <code>GROUP BY</code> блоки данных, удовлетворяющие заданным в <code>HAVING</code> условиям. Это дополнительная возможность “профильтровать” выходной набор.</p>
<p>Условия в <code>HAVING</code> отличаются от условий в <code>WHERE</code>:</p>
<ul>
<li><code>HAVING</code> исключает из результирующего набора данных группы с результатами агрегированных значений;</li>
<li><code>WHERE</code> исключает из расчета агрегатных значений по группировке записи, не удовлетворяющие условию;</li>
<li>в условии поиска <code>WHERE</code> нельзя задавать агрегатные функции.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://kocherov.net/chem-having-otlichaetsya-ot-where/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MSSQL, TSQL, динамический SQL, динамическое формирование запросов</title>
		<link>https://kocherov.net/mssql-tsql-dinamicheskiy-sql-dinamicheskoe-formirovanie-zaprosov/</link>
		<comments>https://kocherov.net/mssql-tsql-dinamicheskiy-sql-dinamicheskoe-formirovanie-zaprosov/#comments</comments>
		<pubDate>Wed, 20 Feb 2013 11:18:24 +0000</pubDate>
		<dc:creator>Pavel Kocherov</dc:creator>
				<category><![CDATA[Работа]]></category>
		<category><![CDATA[mssql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[tsql]]></category>

		<guid isPermaLink="false">http://kocherov.net/?p=203</guid>
		<description><![CDATA[Задача: в stored procedure динамически формировать SQL для получения данных. Динамическими должны быть все части: названия таблиц, количество условий, названия колонок. В идеале нужно просто составлять строку, а потом выполнять запрос из нее, при этом вообще хорошо, если удастся обеспечить параметризацию. Решение: использование sp_executesql Сразу на примере, ситуация. Пусть у нас есть несколько сущностей в [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Задача: в stored procedure динамически формировать SQL для получения данных. Динамическими должны быть все части: названия таблиц, количество условий, названия колонок. В идеале нужно просто составлять строку, а потом выполнять запрос из нее, при этом вообще хорошо, если удастся обеспечить параметризацию.</p>
<p>Решение: использование sp_executesql<br />
Сразу на примере, ситуация.</p>
<p>Пусть у нас есть несколько сущностей в системе. Есть пользователи, есть записи в блоге, есть статьи.<br />
Все они хранятся в трех разных таблицах account, blog_post, content_page (primary keys: account_id, blog_post_id, content_page_id).<br />
В каждой из этих таблиц есть, соответственно, поля acc_created, bp_created, cp_created. И представьте теперь, что в одной из sp нам необходимо за заданному id и типу сущности получить creation date. Можно написать 3 запроса &#8212; легко, ну а если сущностей, скажем, 50? Тогда простое решение становится уж очень некрасивым.</p>
<p>На помощь приходит динамический sql.<br />
<strong>Attention. Я знаю про перфоманс и про все остальное, я знаю что 50 отдельных запросов будут быстрее. Речь не об этом, а о ситуации, когда принято решение, что делать нужно так.</strong></p>
<pre class="brush: sql; title: ; notranslate">
set @sql =     N'select @created =  ' + @pspAbbrev + '_created from ' + @pspFull + ' where ' + @pspFull + '_ID = @id;';

set @params =  N'@id     integer, ' +
	       N'@created   datetime OUTPUT';
			   
exec sp_executesql @sql, @params, @id = @id, @created = @created OUTPUT
</pre>
<p>Прежде всего, нам необходимо определить @pspAbbrev (например, &#8216;usr&#8217;) и @pspFull(например, &#8216;user&#8217;).<br />
После чего сформировать @sql, определить input-output параметры, вызвать sp_executesql и далее пользоваться полученным значением из переменной @created.</p>
]]></content:encoded>
			<wfw:commentRss>https://kocherov.net/mssql-tsql-dinamicheskiy-sql-dinamicheskoe-formirovanie-zaprosov/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL optimization. Join против In и Exists. Что использовать?</title>
		<link>https://kocherov.net/sql-optimization-join-protiv-in-and-exists-chto-ispolzovat/</link>
		<comments>https://kocherov.net/sql-optimization-join-protiv-in-and-exists-chto-ispolzovat/#comments</comments>
		<pubDate>Sun, 09 Dec 2012 14:29:15 +0000</pubDate>
		<dc:creator>Pavel Kocherov</dc:creator>
				<category><![CDATA[Работа]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://kocherov.net/?p=144</guid>
		<description><![CDATA[&#171;Раньше было проще&#187; &#8212; Подумал я, садясь за оптимизацию очередного запроса в SQL management studio. Когда я писал под MySQL, реально все было проще &#8212; или работает, или нет. Или тормозит или нет. Explain решал все мои проблемы, больше ничего не требовалось. Сейчас у меня есть мощная среда разработки, отладки и оптимизации запросов и процедур/функций, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>&#171;Раньше было проще&#187; &#8212; Подумал я, садясь за оптимизацию очередного запроса в SQL management studio. Когда я писал под MySQL, реально все было проще &#8212; или работает, или нет. Или тормозит или нет. Explain решал все мои проблемы, больше ничего не требовалось. Сейчас у меня есть мощная среда разработки, отладки и оптимизации запросов и процедур/функций, и все это нагромождение создает по-моему только больше проблем. А все почему? Потому что встроенный оптимизатор запросов &#8212; зло. Если в MySQL и PostgreSQL я напишу</p>
<pre class="brush: sql; title: ; notranslate">select * from a, b, c where a.id = b.id, b.id = c.id</pre>
<p>и в каждой из табличек будет хотя бы по 5к строк &#8212; все зависнет. И слава богу! Потому что иначе в разработчике, в лучшем случае, вырабатывается ленность писать правильно, а в худшем он вообще не понимает что делает! Ведь этот же запрос в MSSQL пройдет аналогично</p>
<pre class="brush: sql; title: ; notranslate">select * from a join b on a.id = b.id join c on b.id = c.id</pre>
<p>Встроенный оптимизатор причешет быдлозапрос и все будет окей.</p>
<p>Он так же сам решит, что лучше делать &#8212; exist или join и еще много чего. И все будет работать максимально оптимально.</p>
<p>Только есть одно НО. В один прекрасный момент оптимизатор споткнется о сложный запрос и спасует, и тогда вы получите большущую проблему. И получите вы ее, возможно, не сразу, а когда вес таблиц достигнет критической массы.</p>
<p>Так вот к сути статьи. exists и in &#8212; очень тяжелые операции. Фактически это отдельный подзапрос <strong>для каждой</strong> строчки результата. А если еще и присутствует вложенность, то это вообще туши свет. Все будет окей, когда возвращается 1, 10, 50 строк. Вы не почувствуете разницы, а возможно join  будет даже медленнее. Но когда вытаскивается 500 &#8212; начнутся проблемы. 500 подзапросов в рамках одного запроса &#8212; это серьезно.</p>
<p>Пусть с точки зрения человеческого понимания in и exists лучше, но с точки зрения временных затрат для запросов, возвращающих 50+ строк &#8212; они не допустимы.</p>
<p>Нужно оговориться, что естественно, если где-то убывает &#8212; где-то должно прибывать. Да, join более ресурсоемок по памяти, ведь держать единовременно всю таблицу значений и оперировать ею &#8212; накладнее, чем дергать подзапросы для каждой строки, быстро освобождая память. Нужно смотреть конкретно по запросу и замерять &#8212; критично ли будет использование лишней памяти в угоду времени или нет.</p>
<p>Приведу примеры полных аналогий. Вообще говоря, я не встречал еще запросов такой степени сложности, которые не могли бы быть раскручены в каскад join&#8217;ов. Пусть на это уйдет день, но все можно раскрыть.</p>
<pre class="brush: sql; title: ; notranslate">

select * from a where a.id in (select id from b)

select * from a where exists (select top 1 1 from b where b.id = a.id)

select * from a join b on a.id = b.id

</pre>
<pre class="brush: sql; title: ; notranslate">

select * from a where a.id not in (select id from b)

select * from a where not exists (select top 1 1 from b where b.id = a.id)

select * from a left join b on a.id = b.id where b.id is null

</pre>
<p>Повторюсь &#8212; данные примеры MSSQL оптимизатор оптимизирует под максимальную производительность и на таких простейших запросах тупняков не будет никогда.</p>
<p>Рассмотрим теперь пример реального запроса, который пришлось переписывать из-за того что на некоторых выборках он просто намертво зависал (структура очень упрощена и понятия заменены, не нужно пугаться некоей не оптимальности структуры бд).</p>
<p>Нужно вытащить все дубликаты &#171;продуктов&#187; в разных аккаунтах, ориентируясь на параметры продукта, его группы, и группы-родителя, если таковая есть.</p>
<pre class="brush: sql; title: ; notranslate">

select d.PRODUCT_ID
from PRODUCT s, PRODUCT_GROUP sg
left join M_PG_DEPENDENCY sd on (sg.PRODUCT_GROUP_ID = sd.M_PG_DEPENDENCY_CHILD_ID),
PRODUCT d, PRODUCT_GROUP dg
left join M_PG_DEPENDENCY dd on (dg.PRODUCT_GROUP_ID = dd.M_PG_DEPENDENCY_CHILD_ID)
where s.PRODUCT_GROUP_ID=sg.PRODUCT_GROUP_ID
and d.PRODUCT_GROUP_ID=dg.PRODUCT_GROUP_ID
and sg.PRODUCT_GROUP_PERSPEC=dg.PRODUCT_GROUP_PERSPEC
and sg.PRODUCT_GROUP_NAME=dg.PRODUCT_GROUP_NAME
and s.PRODUCT_NAME=d.PRODUCT_NAME
and s.PRODUCT_TYPE=d.PRODUCT_TYPE
and s.PRODUCT_IS_SECURE=d.PRODUCT_IS_SECURE
and s.PRODUCT_MULTISELECT=d.PRODUCT_MULTISELECT
and dg.PRODUCT_GROUP_IS_TMPL=0
and (
(
	    sd.M_PG_DEPENDENCY_CHILD_ID is null
	    and
	    dd.M_PG_DEPENDENCY_CHILD_ID is null
	  )
	  or exists
	  (
		select 1 from PRODUCT_GROUP sg1, PRODUCT_GROUP dg1
		 where sd.M_PG_DEPENDENCY_PARENT_ID = sg1.PRODUCT_GROUP_ID and
		       dd.M_PG_DEPENDENCY_PARENT_ID = dg1.PRODUCT_GROUP_ID and
		       sg1.PRODUCT_GROUP_PERSPEC=dg1.PRODUCT_GROUP_PERSPEC and
		       sg1.PRODUCT_GROUP_NAME=dg1.PRODUCT_GROUP_NAME and
	  )
	)

</pre>
<p>Так вот это тот случай, когда оптимизатор спасовал. И для каждой строчки выполнялся тяжеленный exists, что убивало базу.</p>
<pre class="brush: sql; title: ; notranslate">

select d.PRODUCT_ID
from PRODUCT s
join PRODUCT d on
    s.PRODUCT_TYPE=d.PRODUCT_TYPE
    and s.PRODUCT_NAME=d.PRODUCT_NAME
    and s.PRODUCT_IS_SECURE=d.PRODUCT_IS_SECURE
    and s.PRODUCT_MULTISELECT=d.PRODUCT_MULTISELECT
join PRODUCT_GROUP sg on s.PRODUCT_GROUP_ID=sg.PRODUCT_GROUP_ID
join PRODUCT_GROUP dg on d.PRODUCT_GROUP_ID=dg.PRODUCT_GROUP_ID
    and sg.PRODUCT_GROUP_NAME=dg.PRODUCT_GROUP_NAME
    and sg.PRODUCT_GROUP_PERSPEC=dg.PRODUCT_GROUP_PERSPEC
left join M_PG_DEPENDENCY sd on sg.PRODUCT_GROUP_ID = sd.M_PG_DEPENDENCY_CHILD_ID
left join M_PG_DEPENDENCY dd on dg.PRODUCT_GROUP_ID = dd.M_PG_DEPENDENCY_CHILD_ID
left join PRODUCT_GROUP sgp on sgp.PRODUCT_GROUP_ID = sd.M_PG_DEPENDENCY_PARENT_ID
left join PRODUCT_GROUP dgp on
    dgp.PRODUCT_GROUP_ID = dd.M_PG_DEPENDENCY_PARENT_ID
    and sgp.PRODUCT_GROUP_NAME = dgp.PRODUCT_GROUP_NAME
    and isnull(sgp.PRODUCT_GROUP_IS_TMPL, 0) = isnull(dgp.PRODUCT_GROUP_IS_TMPL, 0)
where
	  (
		sd.M_PG_DEPENDENCY_CHILD_ID is null
		and
		dd.M_PG_DEPENDENCY_CHILD_ID is null
	  )
	  or
	  (
		sgp.PRODUCT_GROUP_NAME is not null
		and
		dgp.PRODUCT_GROUP_NAME is not null
	  )
go

</pre>
<p>После данных преобразований производительность вьюхи увеличилась экспоненциально количеству найденных продуктов. Вернее сказать, время поиска оставалось практически независимым от числа совпадений и было всегда очень маленьким. Как и должно быть.</p>
<p><strong>Это наглядный пример того, как доверие MSSQL оптимизатору может сыграть злую шутку. Не доверяйте ему, не ленитесь, join&#8217;те ручками, каждый раз думайте что лучше в данной ситуации &#8212; exists, in или join.</strong></p>
]]></content:encoded>
			<wfw:commentRss>https://kocherov.net/sql-optimization-join-protiv-in-and-exists-chto-ispolzovat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
