Brain-Dead MySQL选择优化(使用临时,使用Filesort)

Jon*_*ert 5 mysql database query-optimization database-performance

我目前正在开展涉及专利的项目拉动USPTO网站,作为该项目的一部分,我正在使用伊利诺伊大学人员创建的数据库
(论文:http://abel.lis.illinois.edu/UPDC /USPTOPatentsDatabaseConstruction.pdf)
(我正在使用的表略有过时的模式,只缺少非索引/键值:http://i.imgur.com/44LHS3L.png)

现在标题说我正在尝试优化查询:

SELECT 
        PN,
        AN,
        grants.GrantID,
        grants.FileDate,
        grants.IssueDate,
        grants.Kind,
        grants.ApplicationID,
        assignee_g.OrgName,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', assignee_g.City, assignee_g.State, assignee_g.Country) separator ';') as Assignee,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', inventor_g.FirstName, inventor_g.LastName) separator ';') as Inventor,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', inventor_g.City, inventor_g.State, inventor_g.Country) separator ';') as Inventor_address,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', usclass_g.Class, usclass_g.Subclass) separator ';') as USClass,
        intclass_g.Section,
        intclass_g.Class,
        intclass_g.Subclass,
        intclass_g.MainGroup,
        intclass_g.SubGroup
FROM
    (
    SELECT grants.GrantID as CitingID, CitedID as PN, grants2.ApplicationID AS AN
    FROM
        gracit_g, grants, grants as grants2
    Where
        grants.GrantID IN (*A 
                                         couple 
                                           Thousand
                                              keys*)
            and grants.GrantID = gracit_g.GrantID and grants2.GrantID = CitedID 
    LIMIT 500000) tbl1,
             grants, assignee_g, inventor_g, usclass_g, intclass_g
WHERE
    grants.GrantID = tbl1.CitingID
        and grants.GrantID = assignee_g.GrantID
        and grants.GrantID = inventor_g.GrantID
        and grants.GrantID = usclass_g.GrantID
        and grants.GrantID = intclass_g.GrantID
GROUP BY PN, GrantID
LIMIT 50000000
Run Code Online (Sandbox Code Playgroud)

几乎每个专利都被引用它后面的一个引用我想记录专利的信息引用它.我似乎遇到的问题是我的"GROUP BY PN,GrantID"导致"使用临时,使用Filesort",这严重减慢了我的努力.

这就是我的解释给了我的内容(抱歉,如果格式不完整,我找不到如何制作表格)

1
PRIMARY
derived2
ALL
8716
可能的键:null
key:null
key_len:null
ref:null
使用临时; 使用filesort


1
PRIMARY
授予
eq_ref
PRIMARY
PRIMARY
62
tbl1.CitingID
1


1个
PRIMARY
assignee_g
REF
PRIMARY,FK_PublicationID_PUBLICATION_ASSIGNEE_P
PRIMARY
62
tbl1.CitingID
1


1
PRIMARY
intclass_g
ref
PRIMARY,fk_publicationid_PUBLICATION_INTERNATIONALCLASS_P
PRIMARY
62
tbl1.CitingID
1


1
PRIMARY
inventor_g
ref
PRIMARY,fk_PublicationID_Inventor_p
PRIMARY
62
tbl1.CitingID
1


1
PRIMARY
usclass_g
ref
PRIMARY,fk_publicationid_PUBLICATION_USCLASS_P
PRIMARY
62
tbl1.CitingID
2


2
DERIVED
拨款
范围
PRIMARY
PRIMARY
62
ref:null
2179
使用where; 使用索引


2
DERIVED
gracit_g
REF
PRIMARY,FK_PublicationID_PUBLICATION_PCITATION_P,CitedID
PRIMARY
62
uspto_patents.grants.GrantID
4
使用其中


2个
DERIVED
grants2
eq_ref
PRIMARY
PRIMARY
62
uspto_patents.gracit_g.CitedID
1


gracit_g的SHOW CREATE是:

CREATE TABLE `gracit_g` (
`GrantID` varchar(20) NOT NULL,
`Position` int(11) NOT NULL,
`CitedID` varchar(20) DEFAULT NULL,
`Kind` varchar(10) DEFAULT NULL COMMENT 'identify whether citedDoc is a document or foreign patent',
`Name` varchar(100) DEFAULT NULL,
`Date` date DEFAULT NULL,
`Country` varchar(100) DEFAULT NULL,
`Category` varchar(100) DEFAULT NULL,
PRIMARY KEY (`GrantID`,`Position`),
KEY `FK_PublicationID_PUBLICATION_PCITATION_P` (`GrantID`),
KEY `CitedID` (`CitedID`),
CONSTRAINT `FK_GrantID_GRANT_PCITATION_G0` FOREIGN KEY (`GrantID`) REFERENCES `grants`   (`GrantID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Run Code Online (Sandbox Code Playgroud)

资助的SHOW CREATE是:

 CREATE TABLE `grants` (
 `GrantID` varchar(20) NOT NULL,
 `Title` varchar(500) DEFAULT NULL,
 `IssueDate` date DEFAULT NULL,
 `Kind` varchar(2) DEFAULT NULL,
 `USSeriesCode` varchar(2) DEFAULT NULL,
 `Abstract` text,
 `ClaimsNum` int(11) DEFAULT NULL,
 `DrawingsNum` int(11) DEFAULT NULL,
 `FiguresNum` int(11) DEFAULT NULL,
 `ApplicationID` varchar(20) NOT NULL,
 `Claims` text,
 `FileDate` date DEFAULT NULL,
 `AppType` varchar(45) DEFAULT NULL,
 `AppNoOrig` varchar(10) DEFAULT NULL,
 `SourceName` varchar(100) DEFAULT NULL,
 PRIMARY KEY (`GrantID`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8
Run Code Online (Sandbox Code Playgroud)

非常感谢你的时间,不幸的是我必须退休到我的床上,因为现在为时已经太晚了(或者在这一点上很早),我现在继续工作)



一个建议是将其更改为1个查询而不是子查询:

  SELECT 
        gracit_g.citedID,
        info_grant.GrantID,
        info_grant.FileDate,
        info_grant.IssueDate,
        info_grant.Kind,
        info_grant.ApplicationID,
        assignee_g.OrgName,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', assignee_g.City, assignee_g.State, assignee_g.Country) separator ';') as Assignee,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', inventor_g.FirstName, inventor_g.LastName) separator ';') as Inventor,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', inventor_g.City, inventor_g.State, inventor_g.Country) separator ';') as Inventor_address,
        GROUP_CONCAT(DISTINCT CONCAT_WS(', ', usclass_g.Class, usclass_g.Subclass) separator ';') as USClass,
        intclass_g.Section,
        intclass_g.Class,
        intclass_g.Subclass,
        intclass_g.MainGroup,
        intclass_g.SubGroup
FROM
    gracit_g, grants as info_grant, assignee_g, inventor_g, usclass_g, intclass_g
WHERE
        gracit_g.GrantID IN (*KEYS*)
        and info_grant.GrantID = gracit_g.GrantID
        and info_grant.GrantID = assignee_g.GrantID
        and info_grant.GrantID = inventor_g.GrantID
        and info_grant.GrantID = usclass_g.GrantID
        and info_grant.GrantID = intclass_g.GrantID
GROUP BY gracit_g.citedID, info_grant.GrantID
LIMIT 50000000
Run Code Online (Sandbox Code Playgroud)

这已经从21s持续时间/ 10s提取减少到13s持续时间/ 8s提取,我仍然希望改进,因为我有许多键通过.

Ran*_*eed 2

您的查询采用以下形式:

SELECT some_fields
FROM (
    SELECT other_fields
    FROM table1, table2
    WHERE join_condition_table1_table2 AND some_other_condition
) AS subquery, table3
WHERE join_condition_subquery_table3
GROUP BY another_field
Run Code Online (Sandbox Code Playgroud)

您需要将其重写如下:

SELECT some_fields
FROM table1, table2, table3
WHERE
    join_condition_table1_table2
    AND join_condition_subquery_table3 -- actually rewrite this ans a join of either table1 and table3, or table2 and table3
    AND some_other_condition
GROUP BY another_field
Run Code Online (Sandbox Code Playgroud)

正如 @Ollie Jones 所指出的,选择SELECT既不是GROUP BY条件的一部分也不是聚合函数内部的字段(在子句中)是危险的。如果这些字段不唯一依赖于条件中的字段GROUP BY,则这些字段的值未定义。

[编辑]

还有一些建议:

  • gracit_g(citedID, GrantID)按此顺序添加索引( ALTER TABLE gracit_g ADD INDEX(citedID, GrantID);) 并将GROUP BY子句更改为GROUP BY gracit_g.citedID, gracit_g.GrantID。优化器可能会喜欢使用这个索引来计算GROUP BY子句。

  • 如果您的VARCHAR主键实际上是数字,请将其类型更改为合适的整数类型。如果没有,请添加数字代理键并将其用作主键。整数比较要快得多,并且您在所有连接中进行大量比较。

  • 预先计算连接的值CONCAT_WS(', ', assignee_g.City, assignee_g.State, assignee_g.Country) separator ';'),例如在额外的列或额外的表中(后者将需要每个表进行额外的联接)

  • 增加tmp_table_sizemax_heap_table_size服务器选项。如果临时表增长得大于这两个值中的任何一个(以字节为单位),则临时表无法保存在内存中,并将被写入磁盘。您可能会受益于此处异常大的值,因为您正在处理异常大的结果集。

我不知道是否还有其他事情要做。您可能需要考虑返回较小的结果集(更少的列,或更多的过滤器,或更小的LIMIT)。