【问题标题】:MySQL Query Optimization with subqueries and JOINs on large databaseMySQL 查询优化与大型数据库上的子查询和 JOIN
【发布时间】:2020-08-11 07:01:18
【问题描述】:

我是新来的,已经在整个互联网上搜索了解决方案。如果我遗漏了什么,请告诉我!

我使用的 MySQL MariaDB 有几个 百万 个条目。我的查询导致超时。即使增加超时也无济于事。查询的目标是每年检索相关条目。我的查询必须加入总共 5 个表。 (不幸的是,数据库的结构是预定义的,我几乎无法更改)。

您可以在下面找到受影响的查询。 日期存储为 varchar,这就是我使用 LIKE % 运算符的原因。不幸的是,我没有更改它的权限。

    SELECT
    spCit.spPN,
    spCit.ipc1,
    spCit.ipc2,
    tbl_patinfo.pn
FROM
    tbl_patinfo
INNER JOIN(
    SELECT
        spIPC.spPN,
        spIPC.ipc1,
        spIPC.ipc2,
        tbl_patcit.pc_pn AS spDocNr
    FROM
        tbl_patcit
    INNER JOIN(
        SELECT DISTINCT
            tbl_ipc.pn AS spPN,
            tbl_ipc.value AS ipc1,
            tbl_ipc.main_cl AS ipc2
        FROM
            tbl_ipc
        RIGHT JOIN(
            SELECT
                tbl_sp.sp_CompanyAlias,
                OrgName,
                infoPN
            FROM
                tbl_sp
            INNER JOIN(
                SELECT DISTINCT
                    tbl_patinfo.pn AS infoPN,
                    tbl_adr.orgname AS OrgName
                FROM
                    tbl_patinfo
                LEFT JOIN tbl_adr ON tbl_patinfo.pn = tbl_adr.pn
                WHERE
                    tbl_patinfo.pub LIKE "%2004"
            ) AS PatPerYear
        ON
            tbl_sp.sp_CompanyAlias = PatPerYear.Orgname
        ) AS spPatents
    ON
        tbl_ipc.pn = spPatents.infoPN
    ) AS spIPC
ON
    tbl_patcit.pn = spIPC.spPN
) AS spCit
ON
    tbl_patinfo.docnr = spCit.spDocNr

注意:如果我没有进行最后一次 JOIN (tbl_patinfo.docnr = spCit.spDocNr),则整个查询都有效。所以很可能是因为这一步。

Explain Select of the query

提前感谢您的帮助。如果我可以提供任何进一步的信息,请告诉我。

---编辑---

所以我设法更改了日期类型,现在我可以执行查询限制为 50 行。但是没有限制,我仍然会超时(超过 7000 秒的处理时间)。

我还尽可能减少了索引上的 VARCHAR(255)。不确定这是否有影响,但这减少了 key_len (参见最新的解释选择)。 这是新代码:

 SELECT
        spCit.spPN,
        spCit.ipc1,
        spCit.ipc2,
        tbl_patinfo.pn
    FROM
        tbl_patinfo
    INNER JOIN(
        SELECT
            spIPC.spPN,
            spIPC.ipc1,
            spIPC.ipc2,
            tbl_patcit.pc_pn AS spDocNr
        FROM
            tbl_patcit
        INNER JOIN(
            SELECT DISTINCT
                tbl_ipc.pn AS spPN,
                tbl_ipc.value AS ipc1,
                tbl_ipc.main_cl AS ipc2
            FROM
                tbl_ipc
            RIGHT JOIN(
                SELECT
                    tbl_sp.sp_CompanyAlias,
                    OrgName,
                    infoPN
                FROM
                    tbl_sp
                INNER JOIN(
                    SELECT DISTINCT
                        tbl_patinfo.pn AS infoPN,
                        tbl_adr.orgname AS OrgName
                    FROM
                        tbl_patinfo
                    LEFT JOIN tbl_adr ON tbl_patinfo.pn = tbl_adr.pn
                    WHERE
                        YEAR(tbl_patinfo.pub) = 2004
                ) AS PatPerYear
            ON
                tbl_sp.sp_CompanyAlias = PatPerYear.Orgname
            ) AS spPatents
        ON
            tbl_ipc.pn = spPatents.infoPN
        ) AS spIPC
     ON
        tbl_patcit.pn = spIPC.spPN
    ) AS spCit
    ON
        tbl_patinfo.docnr = spCit.spDocNr

Here's the new EXPLAIN select

我非常感谢任何想法!

【问题讨论】:

  • 我对查询一无所知。但是对于数百万个结果,唯一的方法是使用索引字段连接的简单查询或减少要交叉的结果数量。您无法编辑结构,但您可以创建新表或临时表来预处理和分解为查询的更多小问题
  • 是的,抱歉,查询可能会造成混淆。我的第一种方法是将查询拆分为视图并使用 temptable 算法,但这也不起作用。我还在最后一个连接的两列上都放了一个索引 (tbl_patinfo.docnr, tbl_patcit.pc_pn)
  • “无权更改”——预热你的简历。

标签: mysql mariadb query-optimization sql-optimization


【解决方案1】:

你在那个方面不走运。 LIKE '%...' 过滤器是不可索引的。你可以做一些事情,例如创建一个动态列,或由触发器维护的非动态列,其中包含 tbl_patinfo.pub 的反向,然后代替 tbl_patinfo.pub LIKE '%2004' 你可以说 tbl_patinfo.revpub LIKE '4002%'

【讨论】:

  • 谢谢 Gordan,我会试试的。我知道字符串前面的 % 会导致很多性能问题,但没想到你的想法。
猜你喜欢
  • 2016-12-27
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 2020-05-10
  • 1970-01-01
相关资源
最近更新 更多