mysql - 优化运行缓慢的 3 个表的 mysql 连接
问题描述
我继承了一个广告 CRM 应用程序,并且一直难以解决几个缓慢的问题。问题之一是 3 个表的连接查询运行缓慢:
订单包含产品,而产品又包含订单广告。Products 表充当 2 之间的中介。
ads_campaign(订单)- 50,000 行(过去 1 年 12,000 行)
CREATE TABLE `advertiser_campaign` (
`Id` INT(10,0) NOT NULL AUTO_INCREMENT,
`BusinessName` VARCHAR(100) NOT NULL COLLATE 'utf8_general_ci',
`CreatedAt` DATETIME NOT NULL,
`account_id` INT(10,0) NULL DEFAULT NULL,
`is_executed` TINYINT(1) NOT NULL DEFAULT '0',
`order_status` INT(10,0) NULL DEFAULT NULL,
`created_by` INT(10,0) NULL DEFAULT NULL,
PRIMARY KEY (`Id`) USING BTREE,
INDEX `FK_AvertiserCampaign_AccountId` (`account_id`) USING BTREE,
INDEX `CreatedAt` (`CreatedAt`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=53385;
报纸产品投标(产品) - 56,000 行(过去 1 年 13,000 行)
CREATE TABLE `newspaper_product_bid` (
`Id` INT(10,0) NOT NULL AUTO_INCREMENT,
`AdvertiserCampaignId` INT(10,0) NOT NULL,
`Status` INT(10,0) NOT NULL DEFAULT '10',
`CreatedAt` DATETIME NOT NULL,
PRIMARY KEY (`Id`) USING BTREE,
INDEX `FK_NewspaperProductBid_AdvertiserCampaign_idx` (`AdvertiserCampaignId`) USING BTREE,
CONSTRAINT `FK_NewspaperProductBid_AdvertiserCampaign` FOREIGN KEY (`AdvertiserCampaignId`) REFERENCES `iihssp_prod_20210820`.`advertiser_campaign` (`Id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=59246;
insert_usage (ads) - 82,000 行(过去 1 年 18,000 行)
CREATE TABLE `insert_usage` (
`insert_usage_id` INT(10,0) NOT NULL AUTO_INCREMENT,
`publish_date` DATE NULL DEFAULT NULL,
`published` TINYINT(1) NULL DEFAULT NULL COMMENT 'Was this specific ad published',
`bid_id` INT(10,0) NULL DEFAULT NULL,
`ad_status` INT(10,0) NULL DEFAULT NULL,
PRIMARY KEY (`insert_usage_id`) USING BTREE,
INDEX `newspaper_product_bid.id` (`bid_id`) USING BTREE,
INDEX `publish_date` (`publish_date`) USING BTREE,
INDEX `ix_ad_status` (`ad_status`) USING BTREE,
INDEX `published` (`published`) USING BTREE,
---------------------------------------
-- Add this index didn't help either
---------------------------------------
-- INDEX `bid_id_ad_status` (`bid_id`, `ad_status`) USING BTREE,
CONSTRAINT `newspaper_product_bid.id` FOREIGN KEY (`bid_id`) REFERENCES `iihssp_prod_20210820`.`newspaper_product_bid` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=100821;
这是我用于获取销售数据的简化连接语句(更大存储过程的一部分):
SELECT
DATE_FORMAT(iu.publish_date, '%m-%d') AS CurrDate,
ROUND(ifnull(sum(ifnull(iu.ad_price, 0)),0),2) as Printed
FROM insert_usage iu
JOIN newspaper_product_bid as npb on iu.bid_id = npb.id
-- The cuplrit (slows down query by 200%)
AND(iu.ad_status != 7 || iu.ad_status is null) AND npb.`Status` != -10
JOIN advertiser_campaign ac on ac.Id = npb.AdvertiserCampaignId
WHERE iu.published=1
AND DATE(iu.publish_date) BETWEEN DATE_FORMAT(QtrStartDt, '%Y-%m-01') AND CurrentDt
GROUP BY DATE_FORMAT(iu.publish_date, '%m-%d')
我已经在连接中涉及的所有列上都有索引。
当我删除对 iu.ad_status 和 npb.status 的检查时,查询运行速度很快并使用了正确的索引。
如何提高查询速度?
解决方案
没有必要 DATE(iu.publish_date)
;您可以简单地iu.publish_date
在这种情况下使用。当在函数调用(甚至)中隐藏一列时,DATE()
它变得不可“sargeable”并且优化器看不到它。
更改后,此索引可能会有所帮助iu
: Drop INDEX published (published) USING BTREE
and Add
INDEX(published, publish_date)
advertiser_campaign
好像没用过;考虑删除JOIN
它。
为了可读性,请ON
用于定义表格的关联方式;用于WHERE
过滤。也就是说,将其移至WHERE
:
AND(iu.ad_status != 7 || iu.ad_status is null) AND npb.`Status` != -10
(为与“ AND
”保持一致,请使用OR
代替||
。)
CurrentDt
这种“简化”似乎缺少。也许它只是简单的NOW()
?
我猜想这些更改会说服优化器使用我建议的索引而不是您显示的任何一个查询计划。然后,如果它有足够的选择性,它将运行得更快。
推荐阅读
- c++ - 任何人都可以帮助在以下快速排序代码中找到错误,它显示分段错误(SIGSEGV)
- excel - 打开具有特定扩展名的文件
- linux - 有人在 Raspberry pi 3(ARM) 上正确安装了 aws-cli v2(x86_64; zipped) 吗?
- javascript - 如何以角度将字符串解析为特定模式?
- jenkins - 无法在舞台内跳过舞台
- r - R代码逐个打开文件执行操作并关闭打开的文件
- python - 如何使用python中的正则表达式删除列表中的重复行
- c++ - 在半透明窗口下查找像素的颜色
- typescript - 打字稿推断类型而不使用显式类型变量进行回调
- swift - swift - 如何确保最初定义特定属性的协议或类型?