php - 减少 MySQL JOIN 语句执行时间

标签 php mysql left-join 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 ;

最佳答案

将语句拆分为一对 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。这两者都应该减少要处理的行数。

在notification_user表的uid字段上添加索引

在notification_read表的uid字段上添加索引

关于php - 减少 MySQL JOIN 语句执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33754885/

相关文章:

php - MySQL 将某些结果分组到一个数组中

php - 从 csv 文件上传时设置条件

javascript - 使用验证码脚本进行表单验证

php - 我如何分组执行此 mysql 查询

Java + MySQL 或 LDAP 服务器状态

mysql - LEFT JOIN 查询执行时间过长

php - 我可以得到一些调试此正则表达式的帮助吗?

javascript - 发送电子邮件表格并在同一页面上继续

mysql - 这个选择子查询可以避免吗?

left-join - 在 netezza 中使用左连接进行更新