Перейти к контенту

Оптимизация SQL запроса


Рекомендуемые сообщения

Пытаюсь заставить IPB-шную галерею выводить картинки на индексе случайным образом. Первое, что приходит в голову - делать выборку

 

SELECT id FROM ibf_gallery_images WHERE category_id = X ORDER BY RAND() LIMIT 1;

 

Но так уж почему-то исторически сложилось, что половина изображений в этой таблице не имеют никаких связей в поле category_id => под выборку они не подпадают => вариант не прокатывает. Зато у них заполнено поле album_id, а в таблице ibf_gallery_albums есть соответствие между album_id и category_id. Таким образом, зная ID изображения, мы можем выйти на category_id (что мне как раз и нужно) через ibf_gallery_albums. Вывод: нужны вложенные запросы. Для меня эта область темная, так что прошу вашей помощи:

 

 

SELECT id from ibf_gallery_images WHERE album_id = (SELECT id FROM ibf_gallery_albums WHERE category_id = '6' LIMIT 1) ORDER BY RAND()

 

Так работает быстро (0.00 - 0.02), но возвращает случайные ID только из одного альбома.

 

А вот так:

 

 

SELECT id from ibf_gallery_images WHERE album_id = (SELECT id FROM ibf_gallery_albums WHERE category_id = '6' ORDER BY RAND() LIMIT 1) ORDER BY RAND()

 

Работает о-о-о-чень долго (1 сек на запрос), но возвращает именно то, что нужно.

 

При этом сам по себе запрос

 

SELECT id FROM ibf_gallery_albums WHERE category_id = '6' ORDER BY RAND() LIMIT 1

 

выполняется с нормальной скоростью, а вот когда он становится вложенным...

 

Подскажите, как переделать этот запрос таким образом, чтобы он выполнялся с человеческой скоростью?

Ссылка на комментарий
Поделиться на других сайтах

я эту галерею из-за этой исторической особенности переписал почти всю)

при добавлении фотографии в альбом обязательно проверяю ид категории в которой альбом, и пишу в таблицу картинок и тот ид, и другой

после успешного тестирования сделал скрипт, который пересчитал для всех фотографий, у которых были нули в соответственном поле данные заново и теперь у меня этой проблемы нет по умолчанию...

как вариант - сделать именно так и ничего вкладывать не надо будет

Ссылка на комментарий
Поделиться на других сайтах

Терь уже поздняк метаться. Галерея, конечно, кривая до не могу, но что есть - то есть. Вернемся к сабжу.
Ссылка на комментарий
Поделиться на других сайтах

Тогда делать 2 запроса

первый -

SELECT id FROM albums WHERE category_id=6

создать массив идешек

массив implode через запятую

второй -

SELECT id FROM images WHERE category_id=6 OR album_id IN('.$arr.') ORDER BY RAND() LIMIT 1

 

 

 

 

P.S.ну смотря какой поздняк

у меня на тот момент уже было 3000 фоток...

 

какая версия галереи?

почему бы и не сделать так?

Ссылка на комментарий
Поделиться на других сайтах

Наши посетители загрузили 7977 изображений и отправили 3738 комментариев.

 

Версия 2.1. Не хочу исправлять баги IPS, надеюсь, в новой версии повеселее будет, а пока хочется реализовать сабж своими силами, не прибегая к изменениям существующей БД.

Ссылка на комментарий
Поделиться на других сайтах

В принципе, сейчас попробую через два, думаю, получится, но ведь по-идеи это можно и через один сделать как-то? :D Если два по-отдельности работают быстро, почему не могу быстро работать вместе? ;)
Ссылка на комментарий
Поделиться на других сайтах

Блин. Что-то я не осилил короче. Выборка получилась, но работала криво + я еще в последний момент сообразил, что необходимо сравнивать разрешения для отдельного пользователя, а откуда их выдрать и как с ними составить SQL - мне стало лень думать. Столько заморочек = ( Я расчитывал на банальный ORDER BY RAND()...

 

Ежели кому интересно довести до ума, вот то, до чего я дошел:

 

			$cat_sql = mysql_query("SELECT id FROM ibf_gallery_albums WHERE category_id = '".$row['id']."' ORDER BY RAND() LIMIT 1");
		$albums[$k] = @mysql_fetch_array($cat_sql);
		if ($albums[$k]['id'])
		{
		$image_id_sql = mysql_query("SELECT id from ibf_gallery_images WHERE album_id = ".$albums[$k]['id']." ORDER BY RAND() LIMIT 1");
		$ids = @mysql_fetch_array($image_id_sql);
		if (!$ids['id']) { $ids['id'] = $row['last_pic']; }
		//echo "cat[".$row['id']."]".$albums[$row['id']]['id']."=".$ids['id']."; ";
		}
		$k++;
		$ids = @mysql_fetch_array($sql_samp2);
		//echo $albums[$row['id']]['id']." ";
		if( $check_permissions && ! $this->ipsclass->check_perms( $row['perms_thumbs'] ) )
		{
				$this->allowed_cats--;
				continue;
		}

					$this->image_ids[ $row['id'] ] = $ids['id'];//$row['last_pic'];

 

Это в lib_categories.php, в районе 120-130 строки нужно вставить. Там где цикл обработки выборки начинается.

Ссылка на комментарий
Поделиться на других сайтах

довести запросто можно)

из категорий брать пермишн просмотра)

я это тоже дописывал в своей галерее где-то, ща скопипастю...

 

add

ух там жесть)

 

	function read_data ($check_permissions = true, $root='', $parent=0)
{
	$this->ipsclass->DB->simple_construct(array('select'=>'id,category_id',
												'from'  =>'gallery_albums',
												));
	$this->ipsclass->DB->simple_exec();
	while($a = $this->ipsclass->DB->fetch_row())
	{
		$aids[]=$a['id'];
	}
	if(count($aids>0))
	{
		$whereaids=implode(',',$aids);
		$this->ipsclass->DB->simple_construct(array('select'=>'id,category_id',
													'from'  =>'gallery_images',
													'where' =>'album_id IN ('.$whereaids.') OR (album_id=0 AND category_id>0)',
													'group' =>'category_id',
													'order' =>'RAND()',
													));
		$this->ipsclass->DB->simple_exec();
		while($i = $this->ipsclass->DB->fetch_row())
		{
			$cids[$i['category_id']]['image']=$i['id'];
		}			
	}
	// Read the data from the database
	$this->ipsclass->DB->cache_add_query( 'get_all_categories', '', 'gallery_sql_queries' );									 
	$this->ipsclass->DB->simple_exec();  

	/**
	* Any allowed cats?
	**/
	$this->allowed_cats = $this->ipsclass->DB->get_num_rows();

	while ($row = $this->ipsclass->DB->fetch_row())
	{
		if( $check_permissions && ! $this->ipsclass->check_perms( $row['perms_thumbs'] ) )
		{
			$this->allowed_cats--;
			continue;
		}

		$this->image_ids[ $row['id'] ] = $row['last_pic'];
		if($cids[$row['id']]['image']>0)
		{
			$this->image_ids[ $row['id'] ] = $cids[$row['id']]['image'];
		}

		if( $this->restrict && !$row['album_mode'] )
		{
			$this->allowed_cats--;
			continue;
		}

		if (!isset($this->data[ $row['id'] ])) 
		{
			$this->data[ $row['id'] ] = $row;
		}
		else 
		{
			$this->data[ $row['id'] ] = array_merge($this->data[ $row['id'] ],$row);				
		}

		if( $parent == $row['parent'] )
		{
			$this->ordered[] =& $this->data[ $row['id'] ];
		}

		// Let the parent category know they have a child
		$this->data[ $row['parent'] ]['child'][] = $row['id'];

		// Add our own id & our descendants to all the categories above
		if (isset($this->data[ $row['id'] ]['descendants']))
		{
			$to_add = array_merge($this->data[ $row['id'] ]['descendants'], array($row['id']));
		}
		else
		{
			$to_add = array($row['id']);
		}

		//$this->_set_decendants($row['parent'],$to_add);
	}
	$this->data[0]['name'] = $root;
}

Ссылка на комментарий
Поделиться на других сайтах

Я тут наднях опять заморочил свой мозг на тему и понял, что выбирать категории по параметру доступные/недоступные нет смысла: если пользователь не знает о существовании какой-то скрытой категории, то и картинку он не увидет (просто негде), а если знает, но открыть не может - так и быть, пускай на thumb'ы любуется, слюни пускает. Пожалуй, еще поковыряюсь с запросами, правда, пока не понятно, почему мой код, приведенный выше иногда дает сбой...

 

(хочу отладчик... :D )

Ссылка на комментарий
Поделиться на других сайтах

(хочу отладчик... :D )

Дык а в чем проблема? Zend Studio, NuSphere PHPEd, Aptana и т.д.

Отлаживать можно точно так же как в Делфях (не показывается тольк асемблерный код)

Вот тут глянь мы с Song тему затрагивали: http://www.ibresource.ru/forums/index.php?showtopic=48359

Ссылка на комментарий
Поделиться на других сайтах

Фух. Довел код до конца:

 

	function read_data ($check_permissions = true, $root='', $parent=0)
{
	// Read the data from the database
	$this->ipsclass->DB->cache_add_query( 'get_all_categories', '', 'gallery_sql_queries' );																		 
	$this->ipsclass->DB->simple_exec();

	/**
	* Any allowed cats?
	**/
	$this->allowed_cats = $this->ipsclass->DB->get_num_rows();

	while ($row = $this->ipsclass->DB->fetch_row())
	{
		if ($row['album_mode'])
			{
			/*
			Если категория предназначения для размещения альбомов - сперва делаем
			выборку альбомов данной категории, затем делаем выборку изображений из
			данных альбомов.
			*/
			$cat_sql = mysql_query("SELECT id FROM ibf_gallery_albums WHERE category_id = '".$row['id']."' AND public_album = 1 ORDER BY RAND() LIMIT 1");
			//if (mysql_error()){  echo "SELECT FROM ALBUMS: ".mysql_error()."<br>"; } //DEBUG
			$albums[$row['id']] = mysql_fetch_array($cat_sql);

			//if (mysql_error()){  echo "FETCH ALBUMS: ".mysql_error()."<br>"; } //DEBUG
			$images_id_sql = mysql_query("SELECT id from ibf_gallery_images WHERE album_id = ".$albums[$row['id']]['id']." AND approved = 1 ORDER BY RAND() LIMIT 1");
			//if (mysql_error()){  echo "SELECT FROM IMAGES: ".mysql_error()."<br>"; } //DEBUG
			$images_id = mysql_fetch_array($images_id_sql);
			//echo "cat[".$row['id']."]".$albums[$row['id']]['id']."=".$images_id['id']."; ";
			//if (mysql_error()){  echo "FETCH IMAGES: ".mysql_error()."<br>"; } //DEBUG
			}

			else
					{
					/* Если у нас не альбом, а просто категория - делаем выборку изображений и все */
					$images_id_sql = mysql_query("SELECT id from ibf_gallery_images WHERE category_id = ".$row['id']." AND approved = 1 ORDER BY RAND() LIMIT 1");
					//if (mysql_error()){  echo "SELECT FROM IMAGES: ".mysql_error()."<br>"; } //DEBUG
					$images_id = mysql_fetch_array($images_id_sql);
					}

		$row['last_pic'] = 1; //!!!!!!!!!! Без понятия, почему, но только так все работает... !!!!!!!!!!

		if( $check_permissions && ! $this->ipsclass->check_perms( $row['perms_thumbs'] ) )
		{
				$this->allowed_cats--;
				continue;
		}

					$this->image_ids[ $row['id'] ] = $images_id['id'];   //$row['last_pic'];

		if( $this->restrict && !$row['album_mode'] )
		{
				$this->allowed_cats--;
				continue;
		}

		if (!isset($this->data[ $row['id'] ])) 
		{

			$this->data[ $row['id'] ] = $row;
		}
		else 
		{
			$this->data[ $row['id'] ] = array_merge($this->data[ $row['id'] ],$row);				
		}

					if( $parent == $row['parent'] )
					{
							$this->ordered[] =& $this->data[ $row['id'] ];
					}

		// Let the parent category know they have a child
		$this->data[ $row['parent'] ]['child'][] = $row['id'];

		// Add our own id & our descendants to all the categories above
		if (isset($this->data[ $row['id'] ]['descendants']))
		{
			$to_add = array_merge($this->data[ $row['id'] ]['descendants'], array($row['id']));
		}
		else
		{
			$to_add = array($row['id']);
		}

		$this->_set_decendants($row['parent'],$to_add);
	}
			$this->data[0]['name'] = $root;
}

 

Мозг съеден. Подскажите, что делает строчка, отмеченная восклицательными знаками? Я искал-искал, но так и не нашел, где она может себя проявить, ведь от $row['last_pic'] я вроде как избавился...

Ссылка на комментарий
Поделиться на других сайтах

Присоединиться к обсуждению

Вы можете ответить сейчас, а зарегистрироваться позже. Если у вас уже есть аккаунт, войдите, чтобы ответить от своего имени.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вы вставили отформатированный текст.   Удалить форматирование

  Допустимо не более 75 смайлов.

×   Ваша ссылка была автоматически заменена на медиа-контент.   Отображать как ссылку

×   Ваши публикации восстановлены.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Зарузка...
×
×
  • Создать...

Важная информация

Находясь на нашем сайте, вы соглашаетесь на использование файлов cookie, а также с нашим положением о конфиденциальности Политика конфиденциальности и пользовательским соглашением Условия использования.