Медленный запрос с несколькими предложениями where и order by - PullRequest
3 голосов
/ 26 февраля 2012

Я пытаюсь найти способ ускорить медленный (сортировка файлов) запрос MySQL.

Таблицы:

categories (id, lft, rgt)
questions (id, category_id, created_at, votes_up, votes_down)

Пример запроса:

SELECT * FROM questions q 
INNER JOIN categories c ON (c.id = q.category_id)
WHERE c.lft > 1 AND c.rgt < 100
ORDER BY q.created_at DESC, q.votes_up DESC, q.votes_down ASC
LIMIT 4000, 20

Если я удалю предложение ORDER BY, это быстро.Я знаю, что MySQL не нравятся оба порядка DESC и ASC в одном и том же предложении, поэтому я попытался добавить составной индекс (created_at, votes_up) в таблицу questions и удалил q.votes_down ASC из предложения ORDER BY.Это не помогло, и кажется, что предложение WHERE мешает здесь, потому что оно фильтрует по столбцам из другой (categories) таблицы.Однако, даже если бы это сработало, это было бы не совсем правильно, поскольку мне нужно условие q.votes_down ASC.

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

РЕДАКТИРОВАТЬ:

CREATE TABLE `categories` (
  `id` int(11) NOT NULL auto_increment,
  `lft` int(11) NOT NULL,
  `rgt` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `lft_idx` (`lft`),
  KEY `rgt_idx` (`rgt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `questions` (
  `id` int(11) NOT NULL auto_increment,
  `category_id` int(11) NOT NULL,
  `votes_up` int(11) NOT NULL default '0',
  `votes_down` int(11) NOT NULL default '0',
  `created_at` datetime NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `questions_FI_1` (`category_id`),
  KEY `votes_up_idx` (`votes_up`),
  KEY `votes_down_idx` (`votes_down`),
  KEY `created_at_idx` (`created_at`),
  CONSTRAINT `questions_FK_1` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

id select_type table type   possible_keys           key     key_len ref                 rows  Extra
1  SIMPLE      q     ALL    questions_FI_1          NULL    NULL    NULL                31774 Using filesort
1  SIMPLE      c     eq_ref PRIMARY,lft_idx,rgt_idx PRIMARY 4       ttt.q.category_id 1       Using where

Ответы [ 3 ]

1 голос
/ 26 февраля 2012

Попробуйте подзапрос, чтобы получить нужные категории:

SELECT * FROM questions 
WHERE category_id IN ( SELECT id FROM categories WHERE lft > 1 AND rgt < 100 )
ORDER BY created_at DESC, votes_up DESC, votes_down ASC
LIMIT 4000, 20
0 голосов
/ 26 февраля 2012

Попробуйте поместить условия, относящиеся к объединенным таблицам, в предложения ON:

SELECT * FROM questions q 
INNER JOIN categories c ON (c.id = q.category_id AND c.lft > 1 AND c.rgt < 100)
ORDER BY q.created_at DESC, q.votes_up DESC, q.votes_down ASC
LIMIT 4000, 20
0 голосов
/ 26 февраля 2012

Попробуйте выбрать в запросе только то, что вам нужно, вместо SELECT *

Почему бы не использовать SELECT * (ALL) в MySQL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...