【问题标题】:MySQL Join Very SlowMySQL 加入速度很慢
【发布时间】:2013-04-20 16:48:40
【问题描述】:

我们的一个 MySQL 语句有问题。

基本上,以下语句需要 5 秒才能运行。我们已经确诊 这取决于两个 select 语句的连接。 When the select statements are 单独运行它们只需要 0.2 秒,但与 JOIN 结合使用时 需要 5 秒。

您是否可以看到我们做错了什么,或者您能看到更好的 怎么办?

已将索引添加到连接中包含的所有列,但不影响速度

SELECT temp_4.primaryid, temp_1.`subjectID` , temp_4.`testOccasionID` 
,`studyNumbers` ,`testDate` 

FROM (
   SELECT * FROM (
     SELECT primarys.primaryid , q_1 AS `subjectID` , q_2 AS `studyNumbers` FROM 
primarys LEFT OUTER JOIN questions_1_100 ON primarys.primaryid = 
questions_1_100.primaryid WHERE 0 = 0 AND q_1 IS NOT NULL GROUP BY primaryid) AS 
maintable_1 
GROUP BY `subjectID` ) AS temp_1 

JOIN 

(SELECT * FROM 
(SELECT primarys.primaryid , q_1 AS `subjectID` , q_4 AS `testOccasionID` , 
DATE_FORMAT(q_5, '%m/%d/%Y') AS `testDate` FROM primarys LEFT OUTER JOIN 
questions_1_100 ON primarys.primaryid = questions_1_100.primaryid WHERE 0 = 0 AND 
q_1 IS NOT NULL AND q_4 IS NOT NULL GROUP BY primaryid) AS maintable_4 
GROUP BY `subjectID` ,`testOccasionID` ) AS temp_4 

ON temp_1.`subjectID` = temp_4.`subjectID` 

表定义:

CREATE TABLE primarys 
( primaryid BIGINT(20) NOT NULL AUTO_INCREMENT,
  dateinserted DATETIME,
  datemodified DATETIME,
  useridinserted BIGINT(20),
  useridmodified BIGINT(20),
  locked VARCHAR(1) NOT NULL DEFAULT 0, 
  primaryquestionlinks TEXT, 
  PRIMARY KEY (primaryid), 
  FOREIGN KEY (useridinserted) REFERENCES users (userid) ON UPDATE CASCADE ON DELETE SET NULL, 
  FOREIGN KEY (useridmodified) REFERENCES users (userid) ON UPDATE CASCADE ON DELETE SET NULL ) ENGINE=InnoDB;

CREATE TABLE questions_1_100
( primaryid BIGINT(20) NOT NULL,
  q_1 BIGINT(20),
  q_2 VARCHAR(50),
  q_3 BIGINT(20),
  q_4 BIGINT(20),
  q_5 DATE,
  PRIMARY KEY (primaryid),
  FOREIGN KEY (primaryid) REFERENCES primarys (primaryid) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB;

单个行军主体数据如下——顺序为primaryid,q_1,q_2,q_4,q_5:

1    1    01001    NULL    NULL
7286 1    NULL     1       1997-12-18
7287 1    NULL     2       1998-02-25

需要的输出是:

7286 1    01001    1      1997-12-18
7287 1    01001    2      1998-02-25

非常感谢

更进一步……如果 q_1 和 q_4 在两个单独的表中会怎样。比如下面的表结构。我能想到的唯一方法是添加左外连接和几个子查询?

CREATE TABLE primarys 
( primaryid BIGINT(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (primaryid));

CREATE TABLE questions_1_100
( primaryid BIGINT(20) NOT NULL,
q_1 BIGINT(20),
q_2 VARCHAR(50),
PRIMARY KEY (primaryid));

CREATE TABLE questions_101_200
( primaryid BIGINT(20) NOT NULL,
q_4 BIGINT(20),
q_5 DATE,
PRIMARY KEY (primaryid));

INSERT INTO primarys values (1);
INSERT INTO primarys values (7286);
INSERT INTO primarys values (7287);

INSERT INTO questions_1_100 VALUES (1,'1','01001');
INSERT INTO questions_1_100 VALUES (7286,'1','');
INSERT INTO questions_1_100 VALUES (7287,'1','');

INSERT INTO questions_101_200 VALUES (7286,'1','1997-12-18');
INSERT INTO questions_101_200 VALUES (7287,'2','1998-02-25');

【问题讨论】:

  • 如果我们能看到您的数据库结构和一些示例行,可能会有所帮助。
  • 请张贴表结构和解释语句..
  • 是的,我们正在考虑这是否是最优化的表结构。本质上它是一个没有关系连接的大表。有一个表,其中包含引用第二个表中的行的主键。然后它收集与一个对象(主题)相关的所有数据,然后收集与第二个对象(testoccasion)相关的所有数据,然后将它们组合在一起。
  • 请您发布表结构和索引,以便我们向您推荐必要的索引。
  • CREATE TABLE primarys (primaryid BIGINT(20) NOT NULL AUTO_INCREMENT, dateinserted DATETIME, datemodified DATETIME, useridinserted BIGINT(20), useridmodified BIGINT(20), locked VARCHAR(1) NOT NULL DEFAULT 0, primaryquestionlinks TEXT, PRIMARY KEY (primaryid), FOREIGN KEY (useridinserted) REFERENCES users (userid) ON UPDATE CASCADE ON DELETE SET NULL, FOREIGN KEY (useridmodified) REFERENCES users (userid) ON UPDATE CASCADE ON DELETE SET NULL ) ENGINE=InnoDB;跨度>

标签: mysql performance join


【解决方案1】:

试试:

SELECT p.primaryid , 
       q2.q_1 AS `subjectID`, 
       q4.q_4 AS `testOccasionID`, 
       q2.q_2 AS `studyNumbers`,
       DATE_FORMAT(q4.q_5, '%m/%d/%Y') AS `testDate` 
FROM primarys p
JOIN questions_1_100 q2
  ON p.primaryid = q2.primaryid
JOIN questions_1_100 q4 
  ON q2.q_1 = q4.q_1 and q4.q_4 is not null

SQLFiddle here.

一个更简单的版本,测试场合primaryid:

SELECT q4.primaryid , 
       q2.q_1 AS `subjectID`, 
       q4.q_4 AS `testOccasionID`, 
       q2.q_2 AS `studyNumbers`,
       DATE_FORMAT(q4.q_5, '%m/%d/%Y') AS `testDate` 
FROM questions_1_100 q2
JOIN questions_1_100 q4 
  ON q2.q_1 = q4.q_1 and q4.q_4 is not null
where q2.q_2 is not null

SQLFiddle here.

【讨论】:

  • 您好,感谢您的代码,这很有意义,尽管它返回一个空集,而其他代码返回数千行。我看不出有什么不同会使它返回一个空集
  • 嗨,马克,感谢您的帮助。第一个查询返回一个空集,而第二个查询确实以极快的速度获取数据,尽管 studynumbers 列为空
  • @user2324001:两个查询现在怎么样?如果仍有问题,您能否将questions_1_100 中单个匹配主题的数据添加到您的问题中?
  • 第一个再次没有结果,第二个产生更多,包括 q_4 为空的地方。我附上了单个匹配主题的数据,包括所需/预期的输出。再次感谢
  • @user2324001:我已经发布了一个更新版本的查询,它适用于所提供的数据。有趣的是,您的原始查询在运行时不会返回任何数据 - 请参阅:sqlfiddle.com/#!2/ab7bc/7
【解决方案2】:

试试这个查询

您正在创建第二个没有用的内部查询。最好去掉那个。

创建这些索引表questions_1_100复合索引(primaryid, q_1, q_4)

primarys索引(primaryid)

希望这会有所帮助..

SELECT 
  temp_4.primaryid, 
  temp_1.`subjectID` , 
  temp_4.`testOccasionID` ,
  `studyNumbers` ,
  `testDate` 
FROM (
  SELECT 
    primarys.primaryid , 
    q_1 AS `subjectID` , 
    q_2 AS `studyNumbers` 
  FROM 
    primarys 
  LEFT OUTER JOIN 
    questions_1_100 
  ON 
    primarys.primaryid = questions_1_100.primaryid 
  WHERE 
    q_1 IS NOT NULL 
  GROUP BY 
    primaryid, 
    subjectID) AS temp_1 
JOIN 
  (SELECT  
     primarys.primaryid , 
     q_1 AS `subjectID` , 
     q_4 AS `testOccasionID` , 
     DATE_FORMAT(q_5, '%m/%d/%Y') AS `testDate` 
  FROM 
     primarys 
  LEFT OUTER JOIN 
     questions_1_100 
  ON 
     primarys.primaryid = questions_1_100.primaryid 
  WHERE 
     q_1 IS NOT NULL AND 
     q_4 IS NOT NULL 
  GROUP BY 
     primaryid,
     subjectID,
     testOccasionID) AS temp_4 
ON 
  temp_1.`subjectID` = temp_4.`subjectID` 

【讨论】:

  • 我创建了复合索引并运行了更新后的查询,不幸的是它花了更长的时间。它大约 30 秒,仍在计数 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-21
  • 1970-01-01
  • 1970-01-01
  • 2015-05-15
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
相关资源
最近更新 更多