首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >请帮我优化MYSQL查询

请帮我优化MYSQL查询
EN

Database Administration用户
提问于 2019-08-12 10:11:05
回答 1查看 33关注 0票数 0

这个查询非常慢:

代码语言:javascript
运行
复制
SELECT  

    ( 
        SELECT SUM(ile.gross)                   
        FROM item_ledger_entry AS ile 
        WHERE clr.docNr=ile.docNr 
        AND clr.serialNo=ile.serialNo 
        AND clr.productNr=ile.productNr 
        AND (ile.cargoLine=clr.id OR ile.orgLine=clr.id) 
        AND ile.id NOT IN (
                            SELECT MIN(zz.id) 
                            FROM item_ledger_entry AS zz 
                            WHERE zz.docNr=ile.docNr 
                            AND zz.serialNo=ile.serialNo 
                            AND zz.productNr=ile.productNr
                          ) 
        AND Date_format(ile.activityDate, '%Y-%m-%d') <= '2019-08-05' 
        AND ile.status='40' 
    ) AS gross_end_out

FROM cargo_line_receive AS clr 

LEFT JOIN cargo_header_receive AS chr 
ON clr.docNr=chr.docNr  

LEFT JOIN n_items AS ni 
ON clr.productNr=ni.code 

LEFT JOIN item_ledger_entry AS i 
ON clr.docNr=i.docNr AND i.status=40 
AND (i.id=clr.id OR i.orgLine=clr.id)   


WHERE ((clr.status='20' OR clr.status='30') && clr.status!='40')  

AND Date_format(clr.activityDate, '%Y-%m-%d') <= '2019-08-05' 

GROUP BY clr.id, clr.docNr, clr.batchNo, clr.serialNo, clr.productNr
ORDER BY clr.activityDate DESC, clr.id DESC

另外,我只需要看到gross_end_out >0的结果

编辑:根据要求,我添加了表结构:

cargo_header_receive:

代码语言:javascript
运行
复制
CREATE TABLE `cargo_header_receive` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `docNr` VARCHAR(50) NULL DEFAULT '0',

    PRIMARY KEY (`id`),
    INDEX `docNr` (`docNr`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;

cargo_line_receive:

代码语言:javascript
运行
复制
CREATE TABLE `cargo_line_receive` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `docNr` VARCHAR(250) NOT NULL DEFAULT '',
    `batchNo` VARCHAR(250) NULL DEFAULT '',
    `serialNo` VARCHAR(250) NULL DEFAULT '',
    `productNr` VARCHAR(250) NOT NULL DEFAULT '',   
    `activityDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
    `status` INT(11) NOT NULL DEFAULT '0',
    `orgLine` INT(11) NOT NULL DEFAULT '0',

    PRIMARY KEY (`id`),
    INDEX `docNr` (`docNr`),
    INDEX `serialNo` (`serialNo`),
    INDEX `productNr` (`productNr`),
    INDEX `status` (`status`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;

item_ledger_entry:

代码语言:javascript
运行
复制
CREATE TABLE `item_ledger_entry` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `docNr` VARCHAR(250) NOT NULL DEFAULT '0',
    `cargoLine` INT(11) NULL DEFAULT NULL,
    `activityDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
    `productNr` VARCHAR(250) NOT NULL,
    `orgLine` INT(11) NULL DEFAULT '0',
    `status` INT(11) NOT NULL DEFAULT '0',  
    `serialNo` VARCHAR(250) NULL DEFAULT '0',   
    `gross` DECIMAL(20,10) NOT NULL DEFAULT '0.0000000000',

    PRIMARY KEY (`id`),
    INDEX `cargoLine` (`cargoLine`),
    INDEX `orgLine` (`orgLine`),
    INDEX `docNr` (`docNr`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;

n_items:

代码语言:javascript
运行
复制
CREATE TABLE `n_items` (
    `code` VARCHAR(250) NOT NULL,

    PRIMARY KEY (`code`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

使用解释:

代码语言:javascript
运行
复制
id | select_type        | table | type | possible_keys           | key   | key_len | ref                | rows | Extra
---------------------------------------------------------------------------------------------------------------------------------------------------------
1  | PRIMARY            | clr   | ALL  | status                  |       |         |                    | 3043 | Using where; Using temporary; Using filesort
1  | PRIMARY            | chr   | ref  | docNr                   | docNr | 153     | database.clr.docNr | 1    | Using where; Using index
1  | PRIMARY            | i     | ref  | PRIMARY,orgLine,docNr   | docNr | 752     | database.clr.docNr | 5    | Using where
2  | DEPENDENT SUBQUERY | ile   | ref  | cargoLine,orgLine,docNr | docNr | 752     | func               | 5    | Using where
3  | DEPENDENT SUBQUERY | zz    | ref  | docNr                   | docNr | 752     | database.ile.docNr | 5    | Using where

此外,我也不能在gross_end_out中使用WHERE

提前感谢!

EN

回答 1

Database Administration用户

回答已采纳

发布于 2019-08-12 15:48:21

快速解决办法是提供一个体面的“综合”索引

代码语言:javascript
运行
复制
                        SELECT MIN(zz.id) 
                        FROM item_ledger_entry AS zz 
                        WHERE zz.docNr=ile.docNr 
                        AND zz.serialNo=ile.serialNo 
                        AND zz.productNr=ile.productNr

即:

代码语言:javascript
运行
复制
INDEX(docNr, serialNo, productNr, id)

WHERE子句中使用列时,避免在函数中隐藏列:

代码语言:javascript
运行
复制
AND Date_format(activityDate, '%Y-%m-%d') <= '2019-08-05'

-->

代码语言:javascript
运行
复制
AND activityDate < '2019-08-05' + INTERVAL 1 DAY

(这可能有帮助,也可能没有帮助,这取决于我们是否能够创建一个涉及activityDate的有用索引。)

现在来处理

代码语言:javascript
运行
复制
    WHERE clr.docNr=ile.docNr 
    AND clr.serialNo=ile.serialNo 
    AND clr.productNr=ile.productNr 
    AND (ile.cargoLine=clr.id OR ile.orgLine=clr.id)
    AND ile.activityDate < '2019-08-05' + INTERVAL 1 DAY
    AND ile.status='40' 

优化器可以从clr开始,也可以从ile开始。如果它选择ile,则添加

代码语言:javascript
运行
复制
ile: INDEX(status, activityDate) -- in this order
clr: INDEX(docNr, serialNo, productNr)  -- in any order

对于clr,添加

代码语言:javascript
运行
复制
ile: INDEX(docNr, serialNo, productNr,  -- in any order, plus
           status, activityDate         -- in this order

这是:

代码语言:javascript
运行
复制
    ON clr.docNr=i.docNr AND i.status=40 

需求

代码语言:javascript
运行
复制
i:  INDEX(docNr, status)  -- in either order

另外,不要盲目地使用VARCHAR(250);它会以微妙的方式轻微地损害性能。根据您拥有并最终可能拥有的数据,选择一个合理的(但却是保守的)限制。

n_items中还有其他列吗?如果没有,为什么存在该表?为什么会有LEFT JOIN呢?

更多关于复合索引和其他内容的信息:http://mysql.rjweb.org/doc.php/index_烹饪书_mysql

票数 2
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/245120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档