【问题标题】:How to optimize MySQL queries with Joins and subqueries for large datasets (millions of rows)如何使用大型数据集(数百万行)的连接和子查询优化 MySQL 查询
【发布时间】:2015-06-27 05:23:09
【问题描述】:

我正在尝试将国际专利数据库 (PATSTAT) 的四个大型表(35-2 亿行)连接到符合一些要求的被引用最多的前 15 名专利中。

第一个表 (t9) 列出了从一组(系列)申请到另一组的引用。 另一个表 (t1) 基本上将所有内容链接在一起,因为它包含家庭和申请 ID,以及申请年份 表 t2tls209_appln_ipc 用于标识要包含的 appln_id

我最终得出的代码如下:

SELECT t9.cited_docdb_family_id, COUNT(t9.cited_docdb_family_id) AS cited, t3.appln_id
FROM docdb_family_citation t9 
LEFT JOIN 
(SELECT
t1.appln_id, t1.docdb_family_id from tls201_appln t1
LEFT JOIN tls204_appln_prior t2 on t1.appln_id=t2.appln_id 
WHERE
t1.appln_filing_year BETWEEN 2010 AND 2015
AND
t2.appln_id IS NULL
AND
t1.appln_id IN (SELECT distinct appln_id from tls209_appln_ipc where ipc_subclass_symbol in ("A61K", "C07K", "A61P", "Cl2N", "C07D", "Cl2P", "C07H", "C12Q", "C07J"))) t3 ON t9.cited_docdb_family_id=t3.docdb_family_id
GROUP BY t9.cited_docdb_family_id
ORDER BY cited DESC
LIMIT 15

问题是在 PATSTAT 的基于 Web 的在线界面中运行的查询在我的会话超时之前没有收敛。有没有办法提高这个查询的效率?

-编辑-
tls_209_appln_ipc 包含 1.95 亿行 appln_id 加上 ipc_subclass_symbolappln_id 在此表中可能出现零次或多次。在我的查询中,我只需要docdb_family_ids,如果他们链接的appln_ids 的任何 链接到我列出的ipc_subclass_symbols 的任何

【问题讨论】:

  • 你有没有考虑稍微增加wait_timeout? mysql> SHOW VARIABLES LIKE 'wait_timeout';
  • 很遗憾,这不是基于 Web 的 PATSTAT 界面中的选项,只接受选择查询。

标签: mysql group-by subquery left-join large-data


【解决方案1】:

这是您的查询:

SELECT t9.cited_docdb_family_id, COUNT(t9.cited_docdb_family_id) AS cited, t3.appln_id
FROM docdb_family_citation t9 LEFT JOIN 
     (SELECT t1.appln_id, t1.docdb_family_id
      from tls201_appln t1 LEFT JOIN
           tls204_appln_prior t2
           on t1.appln_id=t2.appln_id 
      WHERE t1.appln_filing_year BETWEEN 2010 AND 2015 AND
            t2.appln_id IS NULL AND
            t1.appln_id IN (SELECT distinct appln_id
                            from tls209_appln_ipc
                            where ipc_subclass_symbol in ("A61K", "C07K", "A61P", "Cl2N", "C07D", "Cl2P", "C07H", "C12Q", "C07J"
                                                         )
                           )
           ) t3
      ON t9.cited_docdb_family_id = t3.docdb_family_id
GROUP BY t9.cited_docdb_family_id
ORDER BY cited DESC
LIMIT 15;

此查询有优化空间。首先,应该谨慎使用 MySQL 中的子查询,因为子查询是物化的。您在这里不需要子查询。您可以链接 left join 操作。其次,select distinctin 子查询中没有用处。此外,exists 通常更快。

我将首先将其重写为:

SELECT t9.cited_docdb_family_id, COUNT(t9.cited_docdb_family_id) AS cited, t1.appln_id
FROM docdb_family_citation t9 LEFT JOIN 
     tls201_appln t1
     on t9.cited_docdb_family_id = t1.docdb_family_id and
        t1.appln_filing_year BETWEEN 2010 AND 2015 and
        exists (select 1 from tls209_appln_ipc t209
                where t209.appln_id = t1.appln_id AND
                      t209.ipc_subclass_symbol in ("A61K", "C07K", "A61P", "Cl2N", "C07D", "Cl2P", "C07H", "C12Q", "C07J")
               ) and
        not exists (select 1 from tls204_appln_prior t2
                    where t1.appln_id = t2.appln_id 
                   )
GROUP BY t9.cited_docdb_family_id
ORDER BY cited DESC
LIMIT 15;

对于此查询,您需要以下索引:tls204_appln_prior(appln_id)tls209_appln_ipc(appln_id, ipc_subclass_symbol)tls201_appln(cited_docdb_family_id, appln_id)

我不喜欢on 子句中的existsnot exists,但这似乎是您正在寻找的语义。我强烈怀疑有更好的方法来编写查询,但是您的问题没有提供足够的信息。更好的方法是先聚合t1 表,然后将left join 的结果聚合到t9 表中。但是,嵌套的 left joins 和 exists 会让人感到困惑。

【讨论】:

  • 谢谢,首先我对tls204_appln_prior 的角色添加了一些额外的解释,我认为你关于聚合 t1 表的建议很有潜力,我正在研究它。最后,我无法运行存在的部分,但我对此没有任何经验,因为我对 SQL 来说真的很陌生..
  • 我得到了运行建议的代码(经过小的修复),查询在几分钟内返回结果!但是,出现了一个新问题,被引用列的值太高,可能是由于不需要的累加。结果中cited 的最大值是1651,家庭ID 为25133744,而SELECT COUNT(cited_docdb_family_id )as cited FROM docdb_family_citation WHERE cited_docdb_family_id = "25133744"返回127。关于如何解决这个问题的任何线索?谢谢!
【解决方案2】:

我认为您创建了所需的索引,所以我将传递索引部分。

  • views 用于您的子查询或主查询并在后台更新它们是一个。这可能有助于解决超时问题,因为您将使用视图进行选择,而后台进程将运行您的慢查询。
  • appln_filing_year 上的一个选项是range partitioning,并且可能是 ipc_subclass_symbol 上的列表分区...年份不会是问题,但是 ipc_subclass_symbol,我不知道你在这个中有多少唯一数据,但你可以寻找限制here。在您的情况下,分区返回结果的速度会比正常情况快一些。
  • 您可以在 my.cnf 或运行时为 mysql 增加 wait_timeout。如果您没有更改它,它将是 28800 默认值。但我个人不喜欢这个。

我希望这会有所帮助。

【讨论】:

  • 感谢@mim.,感谢您的提示,不幸的是,视图和等待超时不是一个选项,因为数据库只接受 SELECT 查询。我会尝试分区,但是由于子查询本身在大约五到十秒内运行,我怀疑它是否会有所作为..
【解决方案3】:

我很想先删除内部子查询,这可以作为主子查询中的 JOIN 完成,使用 DISINCT 删除否则会创建的重复项:-

SELECT t9.cited_docdb_family_id, COUNT(t9.cited_docdb_family_id) AS cited, t3.appln_id
FROM docdb_family_citation t9 
LEFT JOIN 
(
    SELECT DISTINCT t1.appln_id, t1.docdb_family_id 
    FROM tls201_appln t1
    INNER JOIN tls209_appln_ipc t99 ON t1.appln_id = t99.appln_id 
    LEFT JOIN tls204_appln_prior t2 ON t1.appln_id = t2.appln_id 
    WHERE t1.appln_filing_year BETWEEN 2010 AND 2015
    AND t2.appln_id IS NULL
    AND t1.appln_id IN 
    AND t99.ipc_subclass_symbol IN ("A61K", "C07K", "A61P", "Cl2N", "C07D", "Cl2P", "C07H", "C12Q", "C07J")
) t3 
ON t9.cited_docdb_family_id = t3.docdb_family_id
GROUP BY t9.cited_docdb_family_id
ORDER BY cited DESC
LIMIT 15

如果 t1.appln_id、t1.docdb_family_id 的重复组合可能在 tls201_appln 表的多行上出现,那么我建议也返回行唯一键(因此 DISTINCT 将返回不同的行而不是不同的值)。

【讨论】:

    【解决方案4】:

    在早期答案的帮助下,给出了我正在寻找的结果的最终代码:

    SELECT t9.cited_docdb_family_id, t99.cited AS cited, t1.appln_id, t1.appln_nr_epodoc
            FROM docdb_family_citation t9 
    INNER JOIN (SELECT cited_docdb_family_id, count(cited_docdb_family_id) as cited FROM docdb_family_citation GROUP BY cited_docdb_family_id) t99 
    ON t9.cited_docdb_family_id = t99.cited_docdb_family_id
    LEFT JOIN 
         tls201_appln t1
         on t9.cited_docdb_family_id = t1.docdb_family_id 
         WHERE
            t1.appln_filing_year BETWEEN 2010 AND 2015 and
            exists (select 1 from tls209_appln_ipc t209
                    where t209.appln_id = t1.appln_id
                      and    t209.ipc_subclass_symbol in ("A61K", "C07K", "A61P", "Cl2N", "C07D", "Cl2P", "C07H", "C12Q", "C07J")
                   ) and
            not exists (select 1 from tls204_appln_prior t2
                        where t1.appln_id = t2.appln_id 
                       )
    GROUP BY t9.cited_docdb_family_id
    ORDER BY cited DESC
    LIMIT 15;`
    

    请注意,与子查询 t99 的连接用于获取正确的 cited 计数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-01
      • 2021-09-24
      • 2023-01-05
      • 2020-05-10
      • 2020-08-11
      • 2015-08-24
      • 2015-05-19
      • 1970-01-01
      相关资源
      最近更新 更多