php - 此查询/数据库不能很好地协同工作

标签 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($_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 秒,这是 Not Acceptable 。我们正在查看大约 800,000 条关于收藏夹的记录和 400,000 条关于故事的记录,此时我不知道下一步该从哪里寻求改进。

这似乎有点令人生畏,所以即使有人能给我指出正确的方向,我也会很高兴。

EXPLAIN 示例输入:

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

既然您选择的是 * 而不是按 auth_id 分组,那么您到底想做什么?

---更新 由于您不需要故事的所有收藏信息,因此此查询应该执行得更好:

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

关于php - 此查询/数据库不能很好地协同工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4321904/

相关文章:

php - 俄语字符编码问题

php - 从数据库生成表单

mysql - 尝试在 osx 上设置 radiant cms

sql-server-2008 - 如何使用 TOP 并有条件地忽略 UNION ALL?

sorting - 如何执行排序+索引同时删除重复项?

php - 如何在 Laravel 5.2 中编写 sql 连接查询

php - 使用 PHP 检查页面加载时表单文件是否存在

php - 当仅存在一个匹配项时 MySQL 返回多个条目(其中一个显示不正确的 URL)

php - 不遵守Where子句

optimization - "DO-178B level A"是否禁止优化编译器?