Php 此查询/数据库不能正常工作
这里有一个问题:Php 此查询/数据库不能正常工作,php,mysql,optimization,Php,Mysql,Optimization,这里有一个问题: SELECT *, COUNT(*) as `numauth` FROM `favorites` as `f1` INNER JOIN `story` as `s1` ON `f1`.`story_id` = `s1`.`story_id` WHERE `f1`.`story_id` != '".addslashes($_REQUEST['storyid'])."' AND `f1`.`story_id` != '".addslashes($_REQ
SELECT
*,
COUNT(*) as `numauth`
FROM `favorites` as `f1`
INNER JOIN `story` as `s1` ON `f1`.`story_id` = `s1`.`story_id`
WHERE `f1`.`story_id` != '".addslashes($_REQUEST['storyid'])."'
AND `f1`.`story_id` != '".addslashes($_REQUEST['storyid2'])."'
AND EXISTS (
SELECT 1 FROM `favorites` as `f2`
WHERE `story_id` = '".addslashes($_REQUEST['storyid'])."'
AND `f2`.`auth_id` = `f1`.`auth_id`)
AND EXISTS (
SELECT 1 FROM `favorites` as `f3`
WHERE `story_id` = '".addslashes($_REQUEST['storyid2'])."'
AND `f3`.`auth_id` = `f1`.`auth_id`)
AND NOT EXISTS (
SELECT 1 FROM `favorites` as `f4`
WHERE `story_id` =
'".addslashes($_REQUEST['exclude'])."'
`f4`.`auth_id` = `f1`.`auth_id`)
GROUP BY `f1`.`story_id`
ORDER BY `numauth` DESC, `story_words` DESC
下面是表格的描述
CREATE TABLE IF NOT EXISTS `favorites` (
`fav_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`auth_id` int(10) unsigned NOT NULL,
`story_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`fav_id`),
UNIQUE KEY `auth_id_2` (`auth_id`,`story_id`),
KEY `auth_id` (`auth_id`),
KEY `story_id` (`story_id`),
KEY `fav_id` (`fav_id`,`auth_id`,`story_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1577985 ;
CREATE TABLE IF NOT EXISTS `story` (
`story_id` int(10) unsigned NOT NULL,
`story_title` varchar(255) NOT NULL,
`story_desc` text NOT NULL,
`story_authid` int(8) unsigned NOT NULL,
`story_authname` varchar(255) NOT NULL,
`story_fandom` varchar(255) NOT NULL,
`story_genre1` tinyint(2) unsigned NOT NULL,
`story_genre2` tinyint(2) unsigned NOT NULL,
`story_created` int(10) unsigned NOT NULL,
`story_updated` int(10) unsigned NOT NULL,
`story_reviews` smallint(5) unsigned NOT NULL,
`story_chapters` smallint(3) unsigned NOT NULL,
`story_rating` tinyint(2) unsigned NOT NULL,
`story_words` mediumint(7) unsigned NOT NULL,
`story_chars` varchar(255) NOT NULL,
UNIQUE KEY `story_id` (`story_id`),
KEY `story_authid` (`story_authid`),
KEY `story_fandom` (`story_fandom`),
KEY `story_authid_2` (`story_authid`,`story_fandom`),
KEY `story_id_2` (`story_id`,`story_authid`),
KEY `story_id_3` (`story_id`,`story_words`),
KEY `story_id_4` (`story_id`,`story_fandom`,`story_words`),
KEY `story_id_5` (`story_id`,`story_reviews`,`story_words`),
KEY `story_words` (`story_words`),
KEY `story_reviews` (`story_reviews`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
现在,我已经做了一些优化,以使查询能够深入到这一点。我在专用服务器上运行,但查询仍需要5-7秒,这是不可接受的。我们正在查看大约800000张收藏夹记录和400000张故事记录,我现在不知道下一步该从哪里改进
这似乎有点让人望而生畏,所以即使有人能给我指出正确的方向,我也会很高兴
用示例输入解释:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY s1 ALL story_id,story_id_2,story_id_3,story_id_4,story_id... NULL NULL NULL 129429 Using where; Using temporary; Using filesort
1 PRIMARY f1 ref story_id story_id 4 fanfic_jordanl_ffrecs.s1.story_id 2 Using where
4 DEPENDENT SUBQUERY f4 eq_ref auth_id_2,auth_id,story_id auth_id_2 8 fanfic_jordanl_ffrecs.f1.auth_id,const 1 Using index
3 DEPENDENT SUBQUERY f3 eq_ref auth_id_2,auth_id,story_id auth_id_2 8 fanfic_jordanl_ffrecs.f1.auth_id,const 1 Using index
2 DEPENDENT SUBQUERY f2 eq_ref auth_id_2,auth_id,story_id auth_id_2 8 fanfic_jordanl_ffrecs.f1.auth_id,const 1 Using index
试试这个:
SELECT f1.*, s1.*, COUNT(*) as `numauth`
FROM `favorites` as `f1`
INNER JOIN `story` as `s1` ON `f1`.`story_id` = `s1`.`story_id`
INNER JOIN (
SELECT auth_id
FROM favorites
WHERE story_id IN ('".addslashes($_REQUEST['storyid'])."', '".addslashes($_REQUEST['storyid2'])."', '".addslashes($_REQUEST['exclude'])."')
GROUP BY auth_id
HAVING Count(IF(story_id = '".addslashes($_REQUEST['exclude'])."', 1, NULL)) = 0 AND Count(*) = 2
) fv ON f1.auth_id = fv.auth_id
WHERE `f1`.`story_id` != '".addslashes($_REQUEST['storyid'])."'
AND `f1`.`story_id` != '".addslashes($_REQUEST['storyid2'])."'
GROUP BY `f1`.`story_id`
ORDER BY `numauth` DESC, `story_words` DESC
既然您选择*而不是按身份验证id分组,那么您到底想做什么
---更新
由于您不需要故事的所有fav信息,因此此查询的性能应该更好:
SELECT s.*, fv.cnt
FROM story s
JOIN (
SELECT fv.story_id, COUNT(*) cnt
FROM favorites fv
JOIN (
SELECT auth_id
FROM favorites
WHERE story_id IN ('".addslashes($_REQUEST['storyid'])."', '".addslashes($_REQUEST['storyid2'])."', '".addslashes($_REQUEST['exclude'])."')
GROUP BY auth_id
HAVING Count(IF(story_id = '".addslashes($_REQUEST['exclude'])."', 1, NULL)) = 0 AND Count(*) = 2
) ufv ON fv.auth_id = ufv.auth_id
WHERE story_id != '".addslashes($_REQUEST['storyid'])."' AND story_id != '".addslashes($_REQUEST['storyid2'])."'
GROUP BY fv.story_id
ORDER BY COUNT(*) DESC
LIMIT 25
) fv ON s.story_id = fv.story_id
ORDER BY fv.cnt DESC, `story_words` DESC
试试这个:
SELECT f1.*, s1.*, COUNT(*) as `numauth`
FROM `favorites` as `f1`
INNER JOIN `story` as `s1` ON `f1`.`story_id` = `s1`.`story_id`
INNER JOIN (
SELECT auth_id
FROM favorites
WHERE story_id IN ('".addslashes($_REQUEST['storyid'])."', '".addslashes($_REQUEST['storyid2'])."', '".addslashes($_REQUEST['exclude'])."')
GROUP BY auth_id
HAVING Count(IF(story_id = '".addslashes($_REQUEST['exclude'])."', 1, NULL)) = 0 AND Count(*) = 2
) fv ON f1.auth_id = fv.auth_id
WHERE `f1`.`story_id` != '".addslashes($_REQUEST['storyid'])."'
AND `f1`.`story_id` != '".addslashes($_REQUEST['storyid2'])."'
GROUP BY `f1`.`story_id`
ORDER BY `numauth` DESC, `story_words` DESC
既然您选择*而不是按身份验证id分组,那么您到底想做什么
---更新
由于您不需要故事的所有fav信息,因此此查询的性能应该更好:
SELECT s.*, fv.cnt
FROM story s
JOIN (
SELECT fv.story_id, COUNT(*) cnt
FROM favorites fv
JOIN (
SELECT auth_id
FROM favorites
WHERE story_id IN ('".addslashes($_REQUEST['storyid'])."', '".addslashes($_REQUEST['storyid2'])."', '".addslashes($_REQUEST['exclude'])."')
GROUP BY auth_id
HAVING Count(IF(story_id = '".addslashes($_REQUEST['exclude'])."', 1, NULL)) = 0 AND Count(*) = 2
) ufv ON fv.auth_id = ufv.auth_id
WHERE story_id != '".addslashes($_REQUEST['storyid'])."' AND story_id != '".addslashes($_REQUEST['storyid2'])."'
GROUP BY fv.story_id
ORDER BY COUNT(*) DESC
LIMIT 25
) fv ON s.story_id = fv.story_id
ORDER BY fv.cnt DESC, `story_words` DESC
注意,不要在整数上使用
addslashes
,只需使用intval()
或(int)
将它们转换为整数即可。另外,更喜欢mysql\u real\u escape\u string
而不是addslashes
。一个小的改进是只做count(fav\u id)
而不是count(*)
@Alex JL,更喜欢PDO而不是mysql\u*函数。你能发布解释输出吗?我已经发布了解释输出。。。我知道它没有为故事表使用索引,但我不太清楚为什么。请注意,不要在int上使用addslashes
,只需使用intval()
或(int)
将它们转换为整数即可。另外,更喜欢mysql\u real\u escape\u string
而不是addslashes
。一个小的改进是只做count(fav\u id)
而不是count(*)
@Alex JL,更喜欢PDO而不是mysql\u*函数。你能发布解释输出吗?我已经发布了解释输出。。。我知道它没有为故事表使用索引,但我不太清楚为什么。数据库中充满了故事和喜欢这些故事的人。用户输入他们喜欢的故事,它会找到所有也喜欢该故事的用户,然后返回该组中具有最多常用收藏夹的故事。是否要返回所有常用故事?还是限制在100左右?(不同之处可能是数据大于排序缓冲区大小)对于最终结果,您是否只需要常见故事和收藏数量?或者您还需要知道哪些用户最喜欢story@user526171:storyid2和排除请求中的元素的目的是什么?我实际上将其限制在前25个结果中,但之前它仍然对100000多行进行排序以获得25个结果。数据库中充满了故事和喜欢这些故事的人。用户输入他们喜欢的故事,它会找到所有也喜欢该故事的用户,然后返回该组中具有最多常用收藏夹的故事。是否要返回所有常用故事?还是限制在100左右?(不同之处可能是数据大于排序缓冲区大小)对于最终结果,您是否只需要常见故事和收藏数量?或者您还需要知道哪些用户最喜欢story@user526171:storyid2和exclude元素在请求中的用途是什么?我实际上将其限制为前25个结果,但之前它仍然对100000多行进行排序以获得25个结果。