Как написать запрос с «USE INDEX (artist_2)» используя kohana 3 orm?

Есть такой код
ORM::factory('Mp3')->where('artist', '=', $artist_name)->where('id', '>', $start_mp3_id)->order_by('id')->limit(10)->find_all();

Было обнаружено, что mysql в процессе этого запроса использует не тот индекс, что надо. В этот запрос надо добавить конструкцию "USE INDEX (artist_2)". Как это сделать? Должно получиться что-то вроде:
SELECT * FROM `mp3s` AS `mp3` USE INDEX (artist_2) WHERE `artist` = 'Аркадий Кобяков' AND `id` > '453509' ORDER BY `id` LIMIT 10
  • Вопрос задан
  • 225 просмотров
Решения вопроса 1
@romalu Автор вопроса
Всем спасибо за помощь, для себя выбрал путь переопределения методов классов в приложении.
Добавляем метод в ORM (application/classes/ORM.php):
<?
class ORM extends Kohana_ORM {

	public function use_index($index)
	{
		$this->_db_pending[] = array(
			'name' => 'use_index',
			'args' => array($index),
		);
		return $this;
	}
}

И прописываем нужное в application/classes/Database/Query/Builder/Select.php
<?
class Database_Query_Builder_Select extends Kohana_Database_Query_Builder_Select {

	protected $_use_index = NULL;

	public function use_index($index)
	{
		$this->_use_index = $index;

		return $this;
	}

	public function compile($db = NULL)
	{
		if ( ! is_object($db))
		{
			// Get the database instance
			$db = Database::instance($db);
		}

		// Callback to quote columns
		$quote_column = array($db, 'quote_column');

		// Callback to quote tables
		$quote_table = array($db, 'quote_table');

		// Start a selection query
		$query = 'SELECT ';

		if ($this->_distinct === TRUE)
		{
			// Select only unique results
			$query .= 'DISTINCT ';
		}

		if (empty($this->_select))
		{
			// Select all columns
			$query .= '*';
		}
		else
		{
			// Select all columns
			$query .= implode(', ', array_unique(array_map($quote_column, $this->_select)));
		}

		if ( ! empty($this->_from))
		{
			// Set tables to select from
			$query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
		}

		if ($this->_use_index !== NULL)
		{
			// Use index
			$query .= " USE INDEX (" . $this->_use_index . ")";
		}

		if ( ! empty($this->_join))
		{
			// Add tables to join
			$query .= ' '.$this->_compile_join($db, $this->_join);
		}

		if ( ! empty($this->_where))
		{
			// Add selection conditions
			$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
		}

		if ( ! empty($this->_group_by))
		{
			// Add grouping
			$query .= ' '.$this->_compile_group_by($db, $this->_group_by);
		}

		if ( ! empty($this->_having))
		{
			// Add filtering conditions
			$query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
		}

		if ( ! empty($this->_order_by))
		{
			// Add sorting
			$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
		}

		if ($this->_limit !== NULL)
		{
			// Add limiting
			$query .= ' LIMIT '.$this->_limit;
		}

		if ($this->_offset !== NULL)
		{
			// Add offsets
			$query .= ' OFFSET '.$this->_offset;
		}

		if ( ! empty($this->_union))
		{
			foreach ($this->_union as $u) {
				$query .= ' UNION ';
				if ($u['all'] === TRUE)
				{
					$query .= 'ALL ';
				}
				$query .= $u['select']->compile($db);
			}
		}

		$this->_sql = $query;

		return parent::compile($db);
	}

}

На заметку, в методе compile я дописал строки в исходный метод compile
if ($this->_use_index !== NULL)
		{
			// USE INDEX
			$query .= " USE INDEX (" . $this->_use_index . ")";
		}

Теперь можно использовать ORM:
ORM::factory('Mp3')->use_index('artist_2')->where('artist', '=', $artist_name)->where('id', '>', $start_mp3_id)->order_by('id')->limit(10)->find_all();
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
ivankomolin
@ivankomolin
При таком виде написания запросов используется Query Builder. Он такого не поддерживает.
Без костылей и доработок самого Query Builder можно используя DB::query например.
Ответ написан
DarkRaven
@DarkRaven
разработка программного обеспечения
А вы вот так попробуйте:
$query = Database::instance('ssd2')->query(Database::SELECT, "SELECT * FROM `mp3s` USE INDEX (artist_2) WHERE `artist` = 'test' AND `id` > 453509 ORDER BY `id` LIMIT 10");

foreach($query as $row)
{
   print_r($row);
}


Я проверил по коду, `query` отдает уже итератор, который можно размотать.
Сигнатура Вашего метода такая:
public function query($type, $sql, $as_object = FALSE, array $params = NULL);
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы