我不是数据库专家,所以我已经存在了一段时间,尽可能多地阅读,并且由于社区的答案,我可以对我的查询和表格结构进行一些更改。即使在阅读了很多东西之后我也陷入了困境,所以我开始提出第一个问题。
我有一个网站,用户发布自己的故事。每个故事都可以有流派,警告,多个作者,分配多个角色等。
我们正在运行MySQL 5.x,表是InnoDB,用PHP编写的网站。使用GROUP_CONCAT在结果上每个故事返回一行。之前使用GROUP BY故事ID尝试过,但每个查询大约需要16秒才能完成,非常慢。使用这个新的,它们取0.175,但是,例如,如果WHERE中的类型不存在,则查询需要23秒!对于测试,每个表有100万条记录,作者表有150万条。我试图添加一些额外的索引来查看MySQL将使用哪一个。
我试图通过一对多的关系来规范化事物。在这里,我将只提供几个表,因为解决方案可能会涵盖整个问题。非常感谢任何帮助,感谢您的时间!
表格
CREATE TABLE `fanfiction_authors` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`penname` varchar(100) NOT NULL,
`penname_url` varchar(100) NOT NULL,
PRIMARY KEY (`uid`),
KEY `penname_url` (`penname_url`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ;
-- --------------------------------------------------------
CREATE TABLE `fanfiction_stories` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(200) NOT NULL,
`sinopse` text NOT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ;
-- --------------------------------------------------------
CREATE TABLE `fanfiction_stories_authors` (
`sid` int(11) NOT NULL,
`uid` int(11) NOT NULL,
KEY `sid_uid` (`sid`,`uid`),
KEY `sid` (`sid`),
KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
CREATE TABLE `fanfiction_stories_genres` (
`key_id` int(11) NOT NULL AUTO_INCREMENT,
`sid` int(11) NOT NULL,
`genre_id` int(11) NOT NULL,
PRIMARY KEY (`key_id`),
KEY `sid` (`sid`),
KEY `genre_id` (`genre_id`),
KEY `sid_genreid` (`sid`,`genre_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ;
-- --------------------------------------------------------
CREATE TABLE `fanfiction_stories_stats` (
`sid` int(11) NOT NULL,
`reviews` int(11) NOT NULL,
`recomendacoes` int(11) NOT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
CREATE TABLE `fanfiction_stories_warnings` (
`key_id` int(11) NOT NULL AUTO_INCREMENT,
`sid` int(11) NOT NULL,
`warning_id` int(11) NOT NULL,
PRIMARY KEY (`key_id`),
KEY `sid` (`sid`),
KEY `warning_id` (`warning_id`),
KEY `warningid_sid` (`sid`,`warning_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ;
----
查询
SELECT
st.sid, st.title, st.sinopse,
(SELECT GROUP_CONCAT(CAST(genre_id AS CHAR)) FROM fanfiction_stories_genres WHERE sid = st.sid) as genres,
stats.reviews, stats.recomendacoes,
(SELECT GROUP_CONCAT(CAST(warning_id AS CHAR)) FROM fanfiction_stories_warnings WHERE sid = st.sid) as warnings_ids
FROM
fanfiction_stories AS st
LEFT JOIN fanfiction_stories_stats AS stats ON st.sid = stats.sid
WHERE
st.sid IN (SELECT sid FROM fanfiction_stories_warnings WHERE warning_id = 5) AND
st.sid IN (SELECT sid FROM fanfiction_stories_genres WHERE genre_id = 300)
ORDER BY
st.sid ASC
LIMIT 20
我无法让我的解释在这里可读,所以我将printscreen上传到Dropbox。无法嵌入图片,因为我在这里是个菜鸟,对不起。
这是我们拥有有效流派时的解释(您将找到流派编号为300的故事)。
http://dl.dropbox.com/u/14508898/Printscreen/stackoverflow_explain_print_001.PNG
这是我们有一个无效类型时的解释(你不会找到类型为900的故事)。
http://dl.dropbox.com/u/14508898/Printscreen/stackoverflow_explain_print_002.PNG
你能帮帮我吗?我的标准化是否正确?我做错了什么?提前致谢!
答案 0 :(得分:1)
您可以使用JOIN来保存2个内部选择,这肯定会在两种情况下加快速度(genre_id = 300
和genre_id = 900
)。
SELECT
st.sid, st.title, st.sinopse,
(SELECT GROUP_CONCAT(CAST(genre_id AS CHAR)) FROM fanfiction_stories_genres WHERE sid = st.sid) as genres,
stats.reviews, stats.recomendacoes,
(SELECT GROUP_CONCAT(CAST(warning_id AS CHAR)) FROM fanfiction_stories_warnings WHERE sid = st.sid) as warnings_ids
FROM
fanfiction_stories AS st
LEFT JOIN fanfiction_stories_stats AS stats ON st.sid = stats.sid
JOIN fanfiction_stories_warnings w ON st.sid = w.sid AND w.warning_id = 5
JOIN fanfiction_stories_genres g ON st.sid = g.sid AND g.genre_id = 300
GROUP BY st.sid
ORDER BY st.sid ASC
LIMIT 20