Сократить время выполнения оператора MySQL JOIN

У меня есть система уведомлений, как в Facebook, с использованием следующего оператора MySQL:

SELECT
n.`id`,n.`content_id`,n.`site_id`,n.`creator_uid`,n.`type`,
nu.`id` AS nuid, nu.`uid` AS nu_uid, nu.`date`,
nr.`id` AS nrid, nr.`uid` AS nr_uid, nr.`is_read`,
u.`gender`

FROM `notification` AS n
LEFT JOIN `notification_user` AS nu ON nu.`nid` = n.`id`
LEFT JOIN `notification_read` AS nr ON nr.`nid` = n.`id`
LEFT JOIN `users` AS u ON u.`id` = nu.`uid`
WHERE
nu.`uid` != '".$_SESSION['uid']."' AND nr.`uid` = '".$_SESSION['uid']."'
OR
(
nu.`uid` = '".$_SESSION['uid']."' AND n.`type` = 'credits'
)
ORDER BY date DESC, nu.`id` DESC

Он должен отображать только уведомления для этого конкретного пользователя, в котором я вошел как. Но теперь у меня более 22500 записей в таблице уведомлений, и я всегда получаю сообщение об ошибке «Превышено максимальное время выполнения».

Можно ли как-то изменить этот запрос, чтобы сократить время получения нужных записей? Может быть, удалить объединение и выполнить больше запросов?

РЕДАКТИРОВАТЬ: Добавлен обзор таблицы

CREATE TABLE IF NOT EXISTS `notification` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content_id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
`creator_uid` int(11) NOT NULL,
`type` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=22759 ;

.

CREATE TABLE IF NOT EXISTS `notification_read` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nid` int(11) NOT NULL,
`uid` int(11) NOT NULL,
`is_read` tinyint(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `nid` (`nid`),
KEY `nid_2` (`nid`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=45342 ;

.

CREATE TABLE IF NOT EXISTS `notification_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nid` int(11) NOT NULL,
`uid` int(11) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=22813 ;

2

Решение

Разделение оператора до пары SELECT и объединение результатов вместе:

(SELECT
n.`id`,n.`content_id`,n.`site_id`,n.`creator_uid`,n.`type`,
nu.`id` AS nuid, nu.`uid` AS nu_uid, nu.`date`,
nr.`id` AS nrid, nr.`uid` AS nr_uid, nr.`is_read`,
u.`gender`
FROM `notification` AS n
INNER JOIN `notification_user` AS nu ON nu.`nid` = n.`id`
LEFT JOIN `notification_read` AS nr ON nr.`nid` = n.`id`
LEFT JOIN `users` AS u ON u.`id` = nu.`uid`
WHERE nu.`uid` = '".$_SESSION['uid']."' AND n.`type` = 'credits')
UNION
(SELECT
n.`id`,n.`content_id`,n.`site_id`,n.`creator_uid`,n.`type`,
nu.`id` AS nuid, nu.`uid` AS nu_uid, nu.`date`,
nr.`id` AS nrid, nr.`uid` AS nr_uid, nr.`is_read`,
u.`gender`
FROM `notification` AS n
LEFT JOIN `notification_user` AS nu ON nu.`nid` = n.`id`
INNER JOIN `notification_read` AS nr ON nr.`nid` = n.`id`
LEFT JOIN `users` AS u ON u.`id` = nu.`uid`
WHERE nu.`uid` != '".$_SESSION['uid']."' AND nr.`uid` = '".$_SESSION['uid']."')
ORDER BY date DESC, nu.`id` DESC

Это должно позволить MySQL эффективно использовать индексы для каждой части запроса. Первая часть запроса требует записи Notification_user, поэтому вы можете использовать INNER JOIN там, в то время как вторая часть требует записи Notification_read, чтобы вы могли использовать INNER JOIN там. Оба из них должны сократить количество строк для обработки.

Добавьте индекс в поле uid в таблице messages_user

Добавьте индекс в поле uid таблицы уведомлений

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]