这个查询非常慢:
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:
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:
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:
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:
CREATE TABLE `n_items` (
`code` VARCHAR(250) NOT NULL,
PRIMARY KEY (`code`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;使用解释:
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
提前感谢!
发布于 2019-08-12 15:48:21
快速解决办法是提供一个体面的“综合”索引
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即:
INDEX(docNr, serialNo, productNr, id)在WHERE子句中使用列时,避免在函数中隐藏列:
AND Date_format(activityDate, '%Y-%m-%d') <= '2019-08-05'-->
AND activityDate < '2019-08-05' + INTERVAL 1 DAY(这可能有帮助,也可能没有帮助,这取决于我们是否能够创建一个涉及activityDate的有用索引。)
现在来处理
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,则添加
ile: INDEX(status, activityDate) -- in this order
clr: INDEX(docNr, serialNo, productNr) -- in any order对于clr,添加
ile: INDEX(docNr, serialNo, productNr, -- in any order, plus
status, activityDate -- in this order这是:
ON clr.docNr=i.docNr AND i.status=40 需求
i: INDEX(docNr, status) -- in either order另外,不要盲目地使用VARCHAR(250);它会以微妙的方式轻微地损害性能。根据您拥有并最终可能拥有的数据,选择一个合理的(但却是保守的)限制。
n_items中还有其他列吗?如果没有,为什么存在该表?为什么会有LEFT JOIN呢?
更多关于复合索引和其他内容的信息:http://mysql.rjweb.org/doc.php/index_烹饪书_mysql
https://dba.stackexchange.com/questions/245120
复制相似问题