Как улучшить этот MySQL запрос в скорости - PullRequest
0 голосов
/ 03 июля 2010

вот оно

SELECT tbl_rls . * , (

SELECT count( * )
FROM `comments`
WHERE `post_id` = `tbl_rls`.`id`
) AS `t_comments`
FROM `tbl_rls`
WHERE 1 =1
AND `status` <> 'denied'
AND (
`id`
IN (

SELECT `rls_id`
FROM `tbl_visitors_logs`
WHERE `date` LIKE '2010-07-02%'
AND `page_type` = 'post'
GROUP BY `rls_id`
ORDER BY count( * ) DESC
)
)
AND (
`cat` = '6'
OR `cat`
IN (

SELECT `id`
FROM `tbl_cats`
WHERE `parent_id` = '6'
)
)
ORDER BY `tbl_rls`.`date` DESC
LIMIT 0 , 20

Это почти убивает БД при выполнении, могут ли некоторые предложить решение, чтобы сделать его быстрым?

Я здесь, чтобы предоставить любую необходимую дополнительную информацию.

Спасибо.

Ответы [ 6 ]

2 голосов
/ 03 июля 2010

Запускали ли вы команду EXPLAIN , чтобы увидеть, какая часть запроса выполняется медленно?

Кроме того, эта строка может быть проблемой: WHERE date LIKE '2010-07-02%' Это может быть причиной того, что столбец даты будет преобразован в строку (пожалуйста, скажите, что это не строка!), Что предотвратит использование любого индекса. Попробуйте WHERE DATE(date) = '2010-07-02' вместо.

1 голос
/ 03 июля 2010

Лучшее, что вы можете сделать, это избавиться от ключевого слова LIKE и просто сказать:

WHERE v.Date > '2010-07-02' AND v.Date < '2010-07-03'

Таким образом, вы получите все за день (или любой другой диапазон дат, который вам нужен),Лучший способ думать об этом - это то, что mySQL придется проходить и оценивать каждую строку, даже если они уже являются полем datetime.Если поле v.Date регулярно ищется, вы можете поместить в него индекс, чтобы ускорить процесс, а затем он ускорит процесс, поскольку у него будет представление, где уже находятся данные.

Вы можететакже используйте COUNT (ID) вместо того, чтобы считать все.Подсчет одного поля вместо 10, 20 или 50 может сэкономить несколько миллисекунд.

1 голос
/ 03 июля 2010
SELECT tbl_rls.*, 
       COUNT(distinct comments.id) AS t_comments 
  FROM tbl_rls 
       JOIN tbl_visitors_logs tvl ON tvl.rls_id = tbl_rls.id
        AND tvl.page_type =  'post'
        AND DATE(tvl.date) = '2010-07-02'
       LEFT JOIN comments ON comments.post_id = tbl_rls.id
       LEFT JOIN tbl_cats ON tbl_cats.id =  cat AND tbl_cats.parent_id = '6'
 WHERE status <> 'denied' 
   AND (cat = 6 OR tbl_cats.id is not null)
 GROUP BY tbl_rls.id                           
 ORDER BY tbl_rls.date DESC 
 LIMIT 0, 20 
1 голос
/ 03 июля 2010

Вот мой переписать ваш запрос:

   SELECT t. *, 
          x.t_comments
     FROM tbl_rls t
LEFT JOIN (SELECT c.post_id,
                  COUNT(*) AS t_comments
             FROM COMMENTS c
         GROUP BY t.post_id) x ON x.post_id = t.id
     JOIN tbl_visitors_logs tvl ON tvl.rls_id = t.id
                               AND tvl.date LIKE '2010-07-02%'
                               AND tvl.page_type = 'post'
    WHERE t.status != 'denied'
      AND (t.cat = '6' OR t.cat IN (SELECT `id`
                                      FROM `tbl_cats`
                                     WHERE `parent_id` = '6'))
ORDER BY t.`date` DESC
   LIMIT 0, 20
1 голос
/ 03 июля 2010

Вы можете попробовать это (без данных трудно проверить)

SELECT r.*, COUNT(c.id) 
FROM tbl_rls r, comments c, tbl_visitors_logs v, tbl_cats t 
WHERE c.post_id = r.id 
    AND v.rls_id = r.id 
    AND t.parent_id = r.cat 
    AND r.status <> 'denied' 
    AND v.`date` LIKE '2010-07-02%' 
    AND page_type = 'post' 
    AND cat = 6 OR t.parent_id = 6 
GROUP BY c.post_id 
ORDER BY r.`date` DESC 
LIMIT 0, 20

Правильна ли эта структура данных?

CREATE TABLE IF NOT EXISTS `tbl_cats` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `tbl_rls` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `status` varchar(10) NOT NULL,
  `cat` int(11) NOT NULL,
  `date` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `tbl_visitors_logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `rls_id` int(11) NOT NULL,
  `date` date NOT NULL,
  `page_type` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `comments` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `post_id` int(11) NOT NULL,
  `commetn` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
1 голос
/ 03 июля 2010

Не используйте подзапросы.Каждый подзапрос выполняется один раз для каждой строки.Поэтому, если внешний запрос возвращает 10 строк, то внутренний запрос будет выполнен 10 раз.

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

Редактировать: не берите в голову этот последний абзац - он выглядел как выбыл подзапрос в подзапросе, но, глядя на него еще раз, вы этого не сделаете.В любом случае, не используйте подзапросы.

...