0 レビュー
1 回答
php-MySQLJOINステートメントの実行時間を短縮します
次のMySQLステートメントを使用したFacebookのような通知システムがあります:
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 ;
わからない
0
レビュー
答え :
解決策:
ステートメントを1組の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を使用できます。一方、2番目の部分ではnotification_readレコードが必要であるため、そこでINNERJOINを使用できます。どちらも、処理する行数を削減する必要があります。
notification_userテーブルのuidフィールドにインデックスを追加します
notification_readテーブルのuidフィールドにインデックスを追加します
わからない
同様の質問
私たちのウェブサイトで同様の質問で答えを見つけてください。