【问题标题】:SQL beginner - Why does my MySQL Join-query use no index / work so slow?SQL 初学者 - 为什么我的 MySQL 连接查询不使用索引/工作这么慢?
【发布时间】:2013-01-29 12:30:57
【问题描述】:

我的 MySQL 5.5 DB 出现以下问题 - 我对此很陌生,所以可能很明显出了什么问题,但我似乎无法理解:

两个表:


表1

CREATE TABLE `sequence_matches` (
    `Sample_ID` INT(6) NOT NULL,
    `Sequence_Match_ID` INT(8) NOT NULL,
    `Start` INT(6) NULL DEFAULT NULL,
    `End` INT(6) NULL DEFAULT NULL,
    `Coverage` DOUBLE(5,2) NULL DEFAULT NULL,
    `Frag_String` VARCHAR(255) NULL DEFAULT NULL,
    `rms_mass_error_prod` DOUBLE(10,4) NULL DEFAULT NULL,
    `rms_rt_error_prod` DOUBLE(10,4) NULL DEFAULT NULL,
  PRIMARY KEY (`Sample_ID`, `Sequence_Match_ID`)
)


表 2

CREATE TABLE `peptide_identifications` (
   `Sample_ID` INT(6) NOT NULL,
   `Peptide_identification_ID` INT(8) NOT NULL,
   `Mass_error` DOUBLE(10,4) NULL DEFAULT NULL,
   `Mass_error_ppm` DOUBLE(10,4) NULL DEFAULT NULL,
   `Score` DOUBLE(10,4) NULL DEFAULT NULL,
   `Type` VARCHAR(45) NULL DEFAULT NULL,
   `global_pept_ID` INT(8) NOT NULL,
  PRIMARY KEY (`Sample_ID`, `Peptide_identification_ID`),
  INDEX `Index` (`global_pept_ID`)
)

每个都包含约 1500 万行。

现在,我想要来自Table2 where global_pept_id = 27443 的所有行,然后使用其中的peptide_identification_id 查询来自Table1 where peptide_identification_id = sequence_match_id 的所有信息。

我尝试了以下说法:

SELECT * from sequence_matches 
JOIN (
  SELECT peptide_identification_id 
  FROM peptide_identifications 
  WHERE global_pept_id = 27443
) as tmp_pept 
ON sequence_match_id = peptide_identification_id; 

这里是该查询的解释:

(点击放大)

现在这个查询非常非常慢(我实际上从未完成它,大约 10 分钟后停止它),我可以想象这是因为没有用于第二个表的索引,尽管两个 ID 都是主键,因此它们应该是索引对吗?

内部选择的结果需要 ~3 sek,如果单独执行,则返回 ~3k 行。所以我认为问题在于进行 3000 * 15mio 比较,因为在 Table2 中检查了每一行。

但是我该如何解决这个问题?

任何帮助表示赞赏 -void

【问题讨论】:

    标签: sql join indexing


    【解决方案1】:

    这可能是因为您要加入子查询。试试:

    SELECT sm.*, pi.peptide_identification_id
    FROM sequence_matches sm
    INNER JOIN peptide_identifications pi
    ON sm.id = pi.peptide_identification_id
    WHERE pi.global_pept_id = 27443
    

    【讨论】:

    • +1 您也可以与 OP 分享 joininner join ;) 以及
    【解决方案2】:

    与其他解决方案略有不同。考虑您首先尝试获得的主要标准......给定全局肽值的那些肽元素。确保您在此表上具有您可能要查询的任何此类条件的索引(您有)。但是,如果您发现您将针对同一个表查询多个 WHERE 条件,请尝试准备/拥有一个有助于满足这两个条件的索引。

    然后,在 PK/FK 关系上对另一个表进行 JOIN 条件以获取这些记录。

    SELECT * 
       from 
          peptide_identification PI
             JOIN sequence_matches SM
                ON PI.peptide_identification_id = SM.sequence_match_id
       WHERE 
          PI.global_pept_id = 27443
    

    没有适当的索引会严重影响查询的性能。您的 Sequence_Matches 表应仅在 (Sequence_match_ID) 上有一个索引,以帮助其优化。将它放在第二个位置(在 sample_id 之后),不会像预期的那样受益。

    【讨论】:

    • 你的答案几乎是正确的;在索引的第二个位置有一列根本不会受益。
    【解决方案3】:

    我认为问题可能是因为您现在正在创建交叉连接 而不是内部连接。您的子查询正在创建笛卡尔 1500 万行 * 300 万行的乘积。

    使用内部联接,您会将该数字减少到 1500 万*3000 行。

    这仍然是一个巨大的数字。在 Sql 端,你可以通过发出来限制它 前 10 名或前 20 名。

    在前端,如果是 C#,你应该使用分页技术,比如 假设 u 数据源上的 gridviewpager 或其他分页技术 将在前端显示结果,该结果将位于顶部 您的 SQL 连接查询和第 20 页的结果。

    【讨论】:

      【解决方案4】:

      提示是避免子选择。有时它们很棒,但通常会导致性能不佳。更好的方法可能是:

      SELECT * from peptide_identification as tmp_pept
      JOIN sequence_matches  
          ON sequence_matches.sequence_match_id = tmp_pept.peptide_identification_id
      WHERE tmp_pept.global_pept_id = 27443
      

      这样行吗?

      编辑:不,真正的问题是 sequence_match_id 上没有索引。添加一个,你可能会没事的。

      【讨论】:

      • 不,还是一样。我确实测试了大约 2 分钟,但没有结果。此外,没有任何子选择的查询的解释与子选择相同 - 它仍然没有使用任何索引来匹配我的 3000 与 1500 万行。
      • 我更新了我的答案;您用于连接的列上没有索引! (它必须是索引的第一列)
      • 所以有一个主键作为 sample_id + sequence_match_id 的索引并不能覆盖?这是否意味着我应该为我计划查询的每一列建立一个索引?
      • 是与否,如果您同时查询sample_id 和sequence_match_id,您的实际索引正是您所需要的。如果您查询 sample_id,您的实际索引也将起作用,但不适用于 sequence_match_id。是的,你需要一个额外的索引。
      • 我也犯了一个轻微的逻辑错误,它应该是ON sequence_matches.sequence_match_id = tmp_pept.peptide_identification_id AND sequence_matches.sample_id = tmp_pept.Sample_ID 抱歉^^ 现在它使用主键作为索引,就像我认为的那样 - 但非常感谢关于一般索引的说明 /* 0 行受影响,找到 3.148 行。 1 个查询的持续时间:1,528 秒。 (+ 21,825 秒网络)*/
      猜你喜欢
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      相关资源
      最近更新 更多