<?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>by Romul &#187; SQL</title>
	<atom:link href="http://byromul.ru/category/development/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://byromul.ru</link>
	<description>То, что интересно мне</description>
	<lastBuildDate>Wed, 25 Jan 2012 21:28:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.4</generator>
		<item>
		<title>SQL. Извращение над группировкой</title>
		<link>http://byromul.ru/2010/02/11/sql-%d0%b3%d1%80%d0%b0%d1%83%d0%bf%d0%bf%d0%b8%d1%80%d0%be%d0%b2%d0%ba/</link>
		<comments>http://byromul.ru/2010/02/11/sql-%d0%b3%d1%80%d0%b0%d1%83%d0%bf%d0%bf%d0%b8%d1%80%d0%be%d0%b2%d0%ba/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 20:39:10 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[оптимизация]]></category>

		<guid isPermaLink="false">http://byromul.ru/?p=244</guid>
		<description><![CDATA[Требуется получить последние темы для каждого рубрики форума. На ум сразу приходит запрос вида: Вариант 1. SELECT id AS rubric_id, ( SELECT id FROM `forum_topic` WHERE rubric_id = `forum_rubric`.id ORDER BY updated DESC LIMIT 1 ) AS last_topic_id FROM `forum_rubric` ; Структуры таблиц. CREATE TABLE `forum_rubric` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID [...]]]></description>
			<content:encoded><![CDATA[<p>Требуется получить последние темы для каждого рубрики форума. На ум сразу приходит запрос вида:</p>
<p><strong>Вариант 1</strong>.<br />
<code><br />
SELECT id AS rubric_id, (<br />
   SELECT id<br />
   FROM `forum_topic`<br />
   WHERE rubric_id = `forum_rubric`.id<br />
   ORDER BY updated DESC<br />
   LIMIT 1<br />
) AS last_topic_id<br />
FROM `forum_rubric` ;<br />
</code></p>
<p><strong>Структуры таблиц</strong>.<br />
<code><br />
CREATE TABLE `forum_rubric` (<br />
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID рубрики форума',<br />
  `status_id` tinyint(3) unsigned NOT NULL COMMENT 'ID статуса',<br />
  `name` varchar(255) DEFAULT NULL COMMENT 'Название',<br />
  PRIMARY KEY (`id`)<br />
) ;<br />
</code><code><br />
CREATE TABLE `forum_topic` (<br />
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID темы',<br />
  `status_id` tinyint(3) unsigned NOT NULL COMMENT 'ID статуса',<br />
  `rubric_id` int(10) unsigned NOT NULL COMMENT 'ID рубрики',<br />
  `title` varchar(255) NOT NULL COMMENT 'Заголовок',<br />
  `added` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Создан',<br />
  `updated` timestamp NULL COMMENT 'Обновлен',<br />
  PRIMARY KEY (`id`),<br />
  KEY `rubric_id` (`rubric_id`,`updated`),<br />
) ;<br />
</code></p>
<p>А вот как можно извратиться и сделать одним запросом:</p>
<p><span id="more-244"></span></p>
<p><strong>Вариант 2</strong>.<br />
<code><br />
SELECT rubric_id, SUBSTRING_INDEX( GROUP_CONCAT( id ORDER BY updated DESC ) , ',', 1 ) AS last_topic_id<br />
FROM `forum_topic`<br />
GROUP BY rubric_id ;<br />
</code></p>
<p>1. группируем по рубрики<br />
2. собираем ID в строку, сортируя в обратном порядке по дате<br />
3. обрезаем до первой запятой</p>
<p>Результате на данных:<br />
- 50 рубрик<br />
- 100.000 тем</p>
<p>Вариант 1:<br />
1.0464 сек, обход ~10.000 записий<br />
Вариант 2:<br />
0.0629 сек, обход всех 100.000 записей</p>
<p>Если в запросе участвует WHERE,<br />
добавим к примеру <code>status_id = 3</code></p>
<p><strong>Вариант 3</strong>.<br />
<code><br />
SELECT id AS rubric_id, (<br />
   SELECT id<br />
   FROM `forum_topic`<br />
   WHERE rubric_id = `forum_rubric`.id AND status_id = 3<br />
   ORDER BY updated DESC<br />
   LIMIT 1<br />
) AS last_topic_id<br />
FROM `bank_forum_rubric` ;<br />
</code></p>
<p>1.0136 сек, обход ~2.000 записей</p>
<p>если добавить ключ на <code>rubric_id + status_id</code>:<br />
0.2013 сек, обход ~450 записей</p>
<p><strong>Вариант 4</strong>.<br />
<code><br />
SELECT rubric_id, SUBSTRING_INDEX( GROUP_CONCAT( id ORDER BY updated DESC ) , ',', 1 ) AS last_topic_id<br />
FROM `forum_topic`<br />
WHERE status_id = 3<br />
GROUP BY rubric_id ;<br />
</code></p>
<p>0.2059 сек, обход ~20.000 записей</p>
<p><strong>Итог</strong>.</p>
<p>Запросы варианта 2 и 4 не используют ключа, проходят по всем записям, они выполняется быстрее или так же, как с вложенным подзапросом (в случае доп. условий).</p>
]]></content:encoded>
			<wfw:commentRss>http://byromul.ru/2010/02/11/sql-%d0%b3%d1%80%d0%b0%d1%83%d0%bf%d0%bf%d0%b8%d1%80%d0%be%d0%b2%d0%ba/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

