复杂的MySQL表架构及其性能

时间:2015-11-14 05:11:46

标签: php mysql sql performance

几年前我为我的mysql表编写了这段代码,现在有了大量的网站流量,我觉得需要改变和改进它。

SELECT ns.*
    FROM stories AS ns
    WHERE section='news' 
      AND title!='draft'
      AND ( 
          FIND_IN_SET('4', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('5', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('6', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('7', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('8', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('9', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('10', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('11', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('12', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('13', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('14', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('15', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('16', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('17', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('18', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('19', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('20', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('21', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('22', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('23', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('24', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('25', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('26', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('27', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('28', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('29', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('30', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('31', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('32', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('33', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('34', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('35', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('36', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('37', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('38', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('39', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('40', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('41', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('42', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('43', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('44', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('45', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('46', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('47', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('48', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('49', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('50', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('51', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('52', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('53', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('54', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('55', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('56', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('57', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('58', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('59', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('60', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('61', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('62', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('63', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('64', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('65', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('66', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('67', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('68', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('69', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('70', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('71', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('72', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('73', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('74', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('75', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('76', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('77', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('78', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('79', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('80', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('81', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('82', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('83', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('84', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('85', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('86', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('87', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('88', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('89', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('90', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('91', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('92', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('94', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('95', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('96', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('97', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('98', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('99', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('100', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('101', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('102', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('103', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('104', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('105', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('106', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('107', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('108', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('109', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('110', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('111', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('112', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('113', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('114', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('115', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('116', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('117', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('118', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('119', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('120', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('121', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('122', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('123', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('125', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('126', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('127', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('128', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('129', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('130', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('131', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('132', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('133', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('134', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('135', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('136', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('137', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('138', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('139', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('140', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('141', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('142', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('144', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('145', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('146', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('147', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('148', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('149', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('150', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('151', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('152', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('153', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('154', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('155', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('156', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('157', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('158', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('159', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('160', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('161', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('162', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('163', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('164', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('165', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('166', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('167', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('168', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('169', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('170', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('171', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('172', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('173', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('174', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('175', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('176', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('177', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('178', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('179', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('180', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('181', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('182', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('183', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('184', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('185', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('186', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('187', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('188', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('189', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('190', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('191', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('192', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('193', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('194', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('195', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('196', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('197', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('198', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('199', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('200', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('201', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('202', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('203', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('204', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('206', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('207', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('208', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('209', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('210', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('211', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('212', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('213', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('214', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('215', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('216', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('217', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('218', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('219', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('220', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('221', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('222', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('223', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('224', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('225', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('226', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('227', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('228', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('229', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('230', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('231', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('232', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('233', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('234', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('235', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('236', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('237', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('238', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('239', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('240', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('241', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('242', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('243', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('244', REPLACE(jjob, '-', ','))
       OR FIND_IN_SET('245', REPLACE(jjob, '-', ','))
   ) AND time <= '2015-11-14 08:30:59'
    ORDER BY ns.hotnews DESC,ns.sid DESC

这是我的表结构:

CREATE TABLE IF NOT EXISTS `stories` (
  `sid` int(11) NOT NULL,
  `catid` int(11) NOT NULL DEFAULT '0',
  `aid` varchar(30) COLLATE utf8_bin NOT NULL,
  `title` text COLLATE utf8_bin,
  `time` datetime DEFAULT NULL,
  `hometext` text COLLATE utf8_bin,
  `bodytext` text COLLATE utf8_bin NOT NULL,
  `hotnews` int(1) NOT NULL DEFAULT '0',
  `tags` varchar(255) COLLATE utf8_bin NOT NULL,
  `approved` tinyint(1) NOT NULL DEFAULT '1',
  `section` varchar(15) COLLATE utf8_bin NOT NULL DEFAULT 'news',
  `rate` int(8) NOT NULL DEFAULT '0',
  `rates_count` int(8) NOT NULL DEFAULT '0',
  `jorganization` int(1) NOT NULL DEFAULT '0',
  `jemployment` int(1) NOT NULL DEFAULT '0',
  `jsex` int(1) NOT NULL DEFAULT '0',
  `jagelimit` int(1) NOT NULL DEFAULT '0',
  `jmarriage` int(1) NOT NULL DEFAULT '0',
  `jduty` int(1) NOT NULL DEFAULT '0',
  `jedu` int(1) NOT NULL DEFAULT '0',
  `jmajor` int(1) NOT NULL DEFAULT '0',
  `jfield` text COLLATE utf8_bin NOT NULL,
  `jjob` text COLLATE utf8_bin NOT NULL,
  `jcity` text COLLATE utf8_bin NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=71693 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `stories`
--
ALTER TABLE `stories`
  ADD PRIMARY KEY (`sid`), ADD KEY `tags` (`tags`), ADD KEY `rate` (`rate`), ADD KEY `rates_count` (`rates_count`);

当我运行查询时,您可以看到它需要超过2秒:

 Showing rows 0 - 24 (27875 total, Query took 2.3042 seconds.) [hotnews: 0 - 0] [sid: 71692 - 71631]

和解释:

enter image description here

3 个答案:

答案 0 :(得分:1)

如果您只打算在最多使用一定数量的行返回,那么最简单(也是最有益)的事情之一就是添加LIMIT

另外还有一些快速的事情可以做:

  1. 仅选择您需要的字段
  2. 添加涵盖的索引(https://www.percona.com/blog/2006/11/23/covering-index-and-prefix-indexes/
  3. 修改/重组jjob

    我不确定jjob在做什么,但你可能需要将它分成另一个表。例如,你可能有一个单独的jjobs表并创建一个连接表(stories_jjobs)来保存每个独特的故事/ jjob实现。

  4. 您可能想要尝试的其他选项是删除所有FIND_IN_SETREPLACE并尝试AND (jjob LIKE %-6% OR jjob LIKE %-9-% etc...)

    之类的内容

    修改

    在仔细查看您的结构后,您可能应将上述内容分成多个表格,以获得长期收益。您的数据库相当小,因此创建一些移动数据的查询应该不会太痛苦。从我可以收集到的j列似乎包含人或用户数据。也许你可以创建一个人或用户表,一个工作表和一个联结表表来加入故事和工作?

答案 1 :(得分:1)

你有一个糟糕的数据结构。所有这些find_in_set()调用都表明数据结构存在问题。它建议您将jjob存储为分隔列表。这使您的数据结构复杂化并使查询更难处理。你应该解决这个问题。

此外,您的查询返回27,875行。这可能需要一些时间,具体取决于行的宽度。所以,2秒可能不会那么糟糕。

与此同时,适当的索引可能有所帮助。请考虑以下索引:

stories(section, time, title, jjob)

这涵盖了where条款,因此可能会有一些性能提升。

要尝试的另一件事是正则表达式。您可以将所有find_in_set()来电替换为:

concat('-', jjob, '-') rlike '-4-|-5-| . . .'

单个正则表达式可能比您当前拥有的几十行更快。但是,我必须强调,正确的解决方案是一个名为StoryJobs的联结表。

答案 2 :(得分:0)

这个综合索引可能有助于进行更多过滤:

INDEX(section, time)

你应该切换到InnoDB。

仅执行一次REPLACE会有所帮助:

SELECT
     FROM  
      ( SELECT
                id,  -- I am assuming the `PRIMARY KEY` for `stories` is `id`
                REPLACE(jjob, '-', ',') AS commas
            FROM  stories
            WHERE  section='news'
              AND  title!='draft'
              AND  time <= '2015-11-14 08:30:59' 
      ) AS x
    JOIN  stories AS ns ON ns.id = x.id
    WHERE FIND_IN_SET('4', commas)
      OR  FIND_IN_SET('5', commas)
      OR  FIND_IN_SET('6', commas)
      OR  FIND_IN_SET('7', commas)
      OR  ...
      OR  FIND_IN_SET('245', commas)
    ORDER BY  ns.hotnews DESC, ns.sid DESC