有没有比多个子查询更好的方法来获得这个,也许有更多的连接?
Posted
技术标签:
【中文标题】有没有比多个子查询更好的方法来获得这个,也许有更多的连接?【英文标题】:Is there a better way to get this than multiple sub-queries, perhaps with more joins? 【发布时间】:2019-04-09 18:55:39 【问题描述】:我有几个表连接在一起,目的是确定“最佳”,即最小的盒子,单个项目或一组这些项目将适合。 只是为了让我“足够接近”,这样我就可以确定不同承运人的该物品或物品的运输成本。
我结合了两个步骤:1 通过 mysql 查询获取每个项目及其测量值,2 通过查询第一个查询的结果来获取“最佳”框,其中一个 mySql 查询为我完成了这两个步骤。 现在的问题是它太慢了,我希望这个查询运行得更快,我已经研究过优化索引,但这似乎没有帮助。我认为也许有更好的方法来构建查询以获得更快的结果集。
SELECT
Listings.PriceCodeDetail.RecNbr AS PCDRecNbr,
(SELECT RecNbr FROM Boxes
WHERE
(
GREATEST(LENGTH, Width, Height) >= GREATEST(atr_grail_live.ip_Spec.ItemLength,atr_grail_live.ip_Spec.ItemWidth,atr_grail_live.ip_Spec.ItemHeight) #GreatestMeasurement
AND LEAST(LENGTH, Width, Height) >= LEAST(atr_grail_live.ip_Spec.ItemLength,atr_grail_live.ip_Spec.ItemWidth,atr_grail_live.ip_Spec.ItemHeight) #LeastMeasurement
AND (LENGTH + Width + Height) - LEAST(LENGTH, Width, Height) - GREATEST(LENGTH, Width, Height) >= (atr_grail_live.ip_Spec.ItemLength+atr_grail_live.ip_Spec.ItemWidth+atr_grail_live.ip_Spec.ItemHeight) - LEAST(atr_grail_live.ip_Spec.ItemLength,atr_grail_live.ip_Spec.ItemWidth,atr_grail_live.ip_Spec.ItemHeight) - GREATEST(atr_grail_live.ip_Spec.ItemLength,atr_grail_live.ip_Spec.ItemWidth,atr_grail_live.ip_Spec.ItemHeight) #MedianMeasurement
)
AND WEIGHT >= (Listings.PriceCodeDetail.QtyBreak * (Listings.ItemListingDetail.ListingQty * atr_grail_live.ip_Spec.ItemWeight)) #TotalWeight
ORDER BY CuIn
LIMIT 1) AS IdealBox # This finds the Longest side, shortest side and middle side and compares it to the Longest, shortest and middle of the item(s) then makes sure the weight is greater that the item(s) weight(s)
FROM
Listings.ItemListingHeader
INNER JOIN Listings.ItemListingDetail ON Listings.ItemListingDetail.HeaderRecNbr = Listings.ItemListingHeader.RecNbr
INNER JOIN Listings.PriceCodeHeader ON Listings.PriceCodeHeader.ListingRecNbr = Listings.ItemListingHeader.RecNbr
INNER JOIN Listings.PriceCodeDetail ON Listings.PriceCodeDetail.HeaderRecNbr = Listings.PriceCodeHeader.RecNbr
INNER JOIN atr_grail_live.ip_Spec ON Listings.ItemListingDetail.IPRecNbr = atr_grail_live.ip_Spec.IP_RecNbr
WHERE
Listings.ItemListingHeader.MarketplaceRecNbr = 1 AND
Listings.PriceCodeHeader.CustomerPriceLevelRecNbr IN (4,5)
AND Listings.ItemListingHeader.RecNbr NOT IN (
SELECT
Listings.ItemListingHeader.RecNbr
FROM
Listings.ItemListingHeader
INNER JOIN Listings.ItemListingDetail ON Listings.ItemListingDetail.HeaderRecNbr = Listings.ItemListingHeader.RecNbr
INNER JOIN Listings.PriceCodeHeader ON Listings.PriceCodeHeader.ListingRecNbr = Listings.ItemListingHeader.RecNbr
INNER JOIN Listings.PriceCodeDetail ON Listings.PriceCodeDetail.HeaderRecNbr = Listings.PriceCodeHeader.RecNbr
INNER JOIN atr_grail_live.ip_Spec ON Listings.ItemListingDetail.IPRecNbr = atr_grail_live.ip_Spec.IP_RecNbr
WHERE
Listings.ItemListingHeader.MarketplaceRecNbr = 1 AND
Listings.PriceCodeHeader.CustomerPriceLevelRecNbr IN (4,5)
AND (atr_grail_live.ip_Spec.ItemLength IS NULL OR atr_grail_live.ip_Spec.ItemLength = '')
GROUP BY Listings.ItemListingHeader.RecNbr
) # This removes from the result set any item(s) that don't have measurements and aren't part of specific groups I have defined, PriceLevel and Marketplace in this instance.
AND atr_grail_live.ip_Spec.IP_RecNbr IN (47467))
# The last AND is only there for now to limit it to one group of items... it will not be used once this is optimized.
我在那里留下了一些 cmets,以便更好地解释我在做什么。目前,此查询大约需要 4 秒并返回 14 行。 如果我删除将其限制为一个项目的最后一行,它将使用超过 250K 的项目组合......所以会花费很长时间。
请注意,每个子查询本身运行得非常快,所以我认为我的索引是正确的。
还要注意,如果不能像这样优化,我可以更改任何表的结构以适应。我在想我可以将盒子和物品存储在长度、宽度、高度中,实际上强制长度为最长,宽度在中间,高度为最短边。那会有帮助吗?
感谢您对此的任何指示。
*** 添加了更多的 cmets **** 如果它有助于我用最大和最小的方式进行所有数学运算的原因是确定最长边,最短边,然后是中间的那个(中位数)。因此,由于我有 3 个值 L、W、H(长度、宽度、高度)并且可以确定 SQL 中的最大值和最小值,因此减去另外两个后剩下的一个是中位数。
* 添加了表格布局 *
CREATE TABLE `ItemListingHeader` (
`RecNbr` int(11) NOT NULL AUTO_INCREMENT,
`SKU` varchar(255) NOT NULL,
`MarketplaceRecNbr` int(11) NOT NULL,
`MarketplaceListingID` varchar(255) NOT NULL,
`MarketplaceShippingTemplateRecNbr` int(11) DEFAULT NULL,
`Status` varchar(1) DEFAULT NULL,
`QtyAvailToReport` int(11) DEFAULT NULL,
`QtyUpdated` datetime DEFAULT NULL,
PRIMARY KEY (`RecNbr`),
UNIQUE KEY `UniqueKey` (`SKU`,`MarketplaceRecNbr`,`MarketplaceListingID`) USING BTREE,
UNIQUE KEY `UniqueKey2` (`SKU`,`MarketplaceRecNbr`) USING BTREE,
KEY `RecNbr` (`RecNbr`)
) ENGINE=InnoDB AUTO_INCREMENT=36351 DEFAULT CHARSET=utf8
CREATE TABLE `ItemListingDetail` (
`RecNbr` int(11) NOT NULL AUTO_INCREMENT,
`HeaderRecNbr` int(11) NOT NULL,
`IPRecNbr` int(11) NOT NULL,
`ListingQty` int(11) DEFAULT NULL,
PRIMARY KEY (`RecNbr`,`HeaderRecNbr`,`IPRecNbr`),
UNIQUE KEY `UniqueKey` (`HeaderRecNbr`,`IPRecNbr`) USING BTREE,
CONSTRAINT `HeaderKey` FOREIGN KEY (`HeaderRecNbr`) REFERENCES `ItemListingHeader` (`RecNbr`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=36344 DEFAULT CHARSET=utf8
CREATE TABLE `PriceCodeHeader` (
`RecNbr` int(11) NOT NULL AUTO_INCREMENT,
`ListingRecNbr` int(11) NOT NULL,
`CustomerPriceLevelRecNbr` int(11) NOT NULL,
`CustomerNbr` int(11) NOT NULL,
PRIMARY KEY (`RecNbr`,`ListingRecNbr`,`CustomerPriceLevelRecNbr`,`CustomerNbr`),
UNIQUE KEY `UniqueKey1` (`ListingRecNbr`,`CustomerPriceLevelRecNbr`) USING BTREE,
KEY `RecNbr` (`RecNbr`),
CONSTRAINT `ListingHeader` FOREIGN KEY (`ListingRecNbr`) REFERENCES `ItemListingHeader` (`RecNbr`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=85976 DEFAULT CHARSET=utf8mb4
CREATE TABLE `PriceCodeDetail` (
`RecNbr` int(11) NOT NULL AUTO_INCREMENT,
`HeaderRecNbr` int(11) NOT NULL,
`PricingMethod` varchar(255) DEFAULT NULL,
`QtyBreak` int(11) NOT NULL,
`Floor` double(11,2) DEFAULT NULL,
`Ceiling` double(11,2) DEFAULT NULL,
`Modifier` double(11,2) DEFAULT NULL,
`Override` double(11,2) DEFAULT NULL,
`AmznMod` double(11,2) DEFAULT NULL,
`PackagingSqFt` double(11,2) DEFAULT NULL,
`LaborMinutes` double(11,2) DEFAULT NULL,
`OtherCosts` double(11,2) DEFAULT NULL,
`FloorMultiplier` double(11,2) DEFAULT NULL,
`CeilingMultiplier` double(11,2) DEFAULT NULL,
`DiscountMultiplier` double(11,2) DEFAULT NULL,
`CurrPrice` double(11,2) DEFAULT NULL,
PRIMARY KEY (`RecNbr`),
UNIQUE KEY `UniqueKey` (`HeaderRecNbr`,`QtyBreak`) USING BTREE,
CONSTRAINT `Header` FOREIGN KEY (`HeaderRecNbr`) REFERENCES `PriceCodeHeader` (`RecNbr`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=242526 DEFAULT CHARSET=utf8mb4
CREATE TABLE `ip_Spec` (
`IP_RecNbr` int(11) NOT NULL DEFAULT '0',
`Amperage` varchar(255) DEFAULT '',
`ANSICode` varchar(255) DEFAULT '',
`Base` varchar(255) DEFAULT '',
`BallastCode` varchar(255) DEFAULT '',
`BeamSpread` varchar(255) DEFAULT '',
`BurnPosition` varchar(255) DEFAULT '',
`Candlepower` varchar(255) DEFAULT '',
`ColorTemp` varchar(255) DEFAULT '',
`ColorTemp_Filter` varchar(255) DEFAULT '',
`Color` varchar(255) DEFAULT '',
`Color_Filter` varchar(255) DEFAULT '',
`CRI` varchar(255) DEFAULT '',
`Diameter` varchar(255) DEFAULT '',
`Diameter_Filter` varchar(255) DEFAULT '',
`DocumentFile1` varchar(255) DEFAULT '',
`DocumentFile2` varchar(255) DEFAULT '',
`DocumentFile3` varchar(255) DEFAULT '',
`DocumentFile4` varchar(255) DEFAULT '',
`DocumentFile5` varchar(255) DEFAULT '',
`DocumentDescription1` varchar(255) DEFAULT '',
`DocumentDescription2` varchar(255) DEFAULT '',
`DocumentDescription3` varchar(255) DEFAULT '',
`DocumentDescription4` varchar(255) DEFAULT '',
`DocumentDescription5` varchar(255) DEFAULT '',
`DocumentType1` varchar(255) DEFAULT '',
`DocumentType2` varchar(255) DEFAULT '',
`DocumentType3` varchar(255) DEFAULT '',
`DocumentType4` varchar(255) DEFAULT '',
`DocumentType5` varchar(255) DEFAULT '',
`Filament` varchar(255) DEFAULT '',
`Finish` varchar(255) DEFAULT '',
`GlassSize` varchar(255) DEFAULT '',
`GlassSize_Filter` varchar(255) DEFAULT '',
`HourLife` varchar(255) DEFAULT '',
`InitialLumens` varchar(255) DEFAULT '',
`ImageFile` varchar(255) DEFAULT '',
`AddtlImage1` varchar(255) DEFAULT '',
`AddtlImage2` varchar(255) DEFAULT '',
`AddtlImage3` varchar(255) DEFAULT '',
`AddtlImage4` varchar(255) DEFAULT '',
`AddtlImage5` varchar(255) DEFAULT '',
`LCL` varchar(255) DEFAULT '',
`Length` varchar(255) DEFAULT '',
`Length_Filter` varchar(255) DEFAULT '',
`Lumens` varchar(255) DEFAULT '',
`Voltage` varchar(255) DEFAULT '',
`Voltage_Filter` varchar(255) DEFAULT '',
`Wattage` varchar(255) DEFAULT '',
`Wattage_Filter` varchar(255) DEFAULT '',
`ShipCode` varchar(255) DEFAULT '',
`SpecStatus` varchar(11) DEFAULT NULL,
`Country_of_Origin` varchar(255) DEFAULT '',
`Contents` varchar(255) DEFAULT '',
`HS_Code` varchar(255) DEFAULT '',
`Dimmable` varchar(1) DEFAULT 'N',
`Enclosure_Rated` varchar(1) DEFAULT 'N',
`Rough_Service` varchar(1) DEFAULT 'N',
`Self_Ballasted` varchar(1) DEFAULT 'N',
`Rapid_Start` varchar(1) DEFAULT 'N',
`Pulse_Start` varchar(1) DEFAULT 'N',
`Covered_Glass` varchar(1) DEFAULT 'N',
`Energy_Star` varchar(1) DEFAULT 'N',
`ROHOS` varchar(1) DEFAULT 'N',
`Description` varchar(255) DEFAULT '',
`BallastType` varchar(255) DEFAULT '',
`BallastStartMethod` varchar(255) DEFAULT '',
`NumberOfLamps` varchar(11) DEFAULT NULL,
`BallastFactor` varchar(11) DEFAULT NULL,
`BallastProductTechnology` varchar(255) DEFAULT NULL,
`MinimumStartTemperature` varchar(11) DEFAULT NULL,
`TotalHarmonicDistortion` varchar(11) DEFAULT NULL,
`EmergencyBallast` varchar(1) DEFAULT 'N',
`CurrentType` varchar(255) DEFAULT '',
`OutputCurrent` varchar(11) DEFAULT NULL,
`OutputCurrentUnitOfMeasure` varchar(255) DEFAULT '',
`OutputVoltage` varchar(11) DEFAULT NULL,
`OutputVoltageUnitOfMeasure` varchar(255) DEFAULT '',
`PowerFactor` varchar(11) DEFAULT NULL,
`Efficiency` varchar(11) DEFAULT NULL,
`Programmable` varchar(1) DEFAULT 'N',
`MinimumWattage` varchar(11) DEFAULT NULL,
`MaximumWattage` varchar(11) DEFAULT NULL,
`HousingMaterial` varchar(255) DEFAULT '',
`LenseMaterial` varchar(255) DEFAULT '',
`MountingStyle` varchar(255) DEFAULT '',
`LightSourceType` varchar(255) DEFAULT '',
`ReflectorType` varchar(255) DEFAULT '',
`IntegratedLightSource` varchar(1) DEFAULT 'N',
`PhotoCellIncluded` varchar(1) DEFAULT 'N',
`SpecsComplete` varchar(1) DEFAULT 'N',
`LocationRating` varchar(255) DEFAULT '',
`ItemLength` varchar(11) DEFAULT NULL,
`ItemLengthUnitOfMeasure` varchar(255) DEFAULT '',
`ItemWidth` varchar(11) DEFAULT NULL,
`ItemWidthUnitOfMeasure` varchar(255) DEFAULT '',
`ItemHeight` varchar(11) DEFAULT NULL,
`ItemHeightUnitOfMeasure` varchar(255) DEFAULT '',
`ItemWeight` varchar(11) DEFAULT NULL,
`ItemWeightUnitOfMeasure` varchar(255) DEFAULT '',
`ProductFamily` varchar(255) DEFAULT '',
`ShortDescription` varchar(255) DEFAULT '',
`LongDescription` text,
`InternalNotes` tinytext,
`BulletPoint1` varchar(255) DEFAULT '',
`BulletPoint2` varchar(255) DEFAULT '',
`BulletPoint3` varchar(255) DEFAULT '',
`BulletPoint4` varchar(255) DEFAULT '',
`BulletPoint5` varchar(255) DEFAULT '',
`WarrantyYears` varchar(11) DEFAULT NULL,
`ETL` varchar(1) DEFAULT 'N',
`CE` varchar(1) DEFAULT 'N',
`UL` varchar(1) DEFAULT 'N',
`DLC` varchar(1) DEFAULT 'N',
`TCLP` varchar(1) DEFAULT 'N',
`IPRated` varchar(1) DEFAULT 'N',
`IPRating` varchar(11) DEFAULT NULL,
`Standby` varchar(1) DEFAULT 'N',
`CeramicMetalHalide` varchar(1) DEFAULT 'N',
`UVProtected` varchar(1) DEFAULT 'N',
`LIFCode` varchar(255) DEFAULT '',
`EnergySaver` varchar(1) DEFAULT 'N',
`ElectricalRequirements` varchar(255) DEFAULT '',
`LumensPerWatt` varchar(11) DEFAULT NULL,
`Disclaimer` text,
`InputElectricalPolarity` varchar(255) DEFAULT '',
`Atmosphere` varchar(255) DEFAULT '',
`BaseMaterial` varchar(255) DEFAULT '',
`GlassMaterial` varchar(255) DEFAULT '',
`DimmablePercentage` varchar(11) DEFAULT NULL,
`ServiceType` varchar(255) DEFAULT '',
`GlassShape` varchar(255) DEFAULT '',
`OutputElectricalPolarity` varchar(255) DEFAULT NULL,
`BeamSpreadDesc` varchar(255) DEFAULT NULL,
`Case1Description` varchar(255) DEFAULT NULL,
`Case1Qty` varchar(255) DEFAULT NULL,
`Case1Length` varchar(255) DEFAULT NULL,
`Case1Width` varchar(255) DEFAULT NULL,
`Case1Height` varchar(255) DEFAULT NULL,
`Case1Weight` varchar(255) DEFAULT NULL,
`Case1GTIN` varchar(255) DEFAULT NULL,
`Case1EAN` varchar(255) DEFAULT NULL,
`Case2Description` varchar(255) DEFAULT NULL,
`Case2Qty` varchar(255) DEFAULT NULL,
`Case2Length` varchar(255) DEFAULT NULL,
`Case2Width` varchar(255) DEFAULT NULL,
`Case2Height` varchar(255) DEFAULT NULL,
`Case2Weight` varchar(255) DEFAULT NULL,
`Case2GTIN` varchar(255) DEFAULT NULL,
`Case2EAN` varchar(255) DEFAULT NULL,
`Case3Description` varchar(255) DEFAULT NULL,
`Case3Qty` varchar(255) DEFAULT NULL,
`Case3Length` varchar(255) DEFAULT NULL,
`Case3Width` varchar(255) DEFAULT NULL,
`Case3Height` varchar(255) DEFAULT NULL,
`Case3Weight` varchar(255) DEFAULT NULL,
`Case3GTIN` varchar(255) DEFAULT NULL,
`Case3EAN` varchar(255) DEFAULT NULL,
`Case4Description` varchar(255) DEFAULT NULL,
`Case4Qty` varchar(255) DEFAULT NULL,
`Case4Length` varchar(255) DEFAULT NULL,
`Case4Width` varchar(255) DEFAULT NULL,
`Case4Height` varchar(255) DEFAULT NULL,
`Case4Weight` varchar(255) DEFAULT NULL,
`Case4GTIN` varchar(255) DEFAULT NULL,
`Case4EAN` varchar(255) DEFAULT NULL,
PRIMARY KEY (`IP_RecNbr`),
UNIQUE KEY `IpRec` (`IP_RecNbr`) USING BTREE,
KEY `SpecStatus` (`SpecStatus`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=ascii
CREATE TABLE `Boxes` (
`RecNbr` int(10) NOT NULL AUTO_INCREMENT,
`Length` int(10) NOT NULL,
`Width` int(10) NOT NULL,
`Height` int(10) NOT NULL,
`Weight` decimal(10,1) NOT NULL,
`CuIn` int(10) NOT NULL,
PRIMARY KEY (`RecNbr`)
) ENGINE=InnoDB AUTO_INCREMENT=184656 DEFAULT CHARSET=utf8mb4
【问题讨论】:
请为查询中的所有表提供SHOW CREATE TABLE tablename
输出。
好主意!谢谢...我添加了它们。
好的,让我们弄清楚应该把注意力集中在哪里。尝试在您的选择中删除子查询,然后重新运行查询(至少两次,只报告最后一个结果。)执行需要多长时间?如果很快,那么我们知道子查询是主要问题。如果没有变化,那么我们知道 SELECT 中的子查询与速度无关。如果只是一些改进,那么我们需要修复它和主查询。
打破它...明白了... 好的,如果我在选择中删除子查询,查询将在 0.626 秒内运行,不到一秒即可返回 14 行。如果我使用主查询中的一条记录自行运行子查询,则需要 0.226 秒……超级快。那么也许没有子查询的 .795 的初始查询实际上是需要优化的?
好的,这很有帮助!我采用子查询部分并在 Boxes 表上为长度、宽度、高度、重量、CuIn 的每个单独字段建立索引,子查询现在下降到 0.001 秒......所以我再次运行我的主查询,它我的 14 行现在下降到大约一秒钟!现在我需要继续前进,让它变得更好,因为如果我能做得更快,1 秒 x 250K 仍然太长。优秀的!这很有趣!
【参考方案1】:
您的NOT IN
where 声明似乎没有必要。我建议将其替换为
atr_grail_live.ip_Spec.ItemLength IS NOT NULL
AND atr_grail_live.ip_Spec.ItemLength <> ''
在主查询中。
这应该提供相同的结果,但不需要 NOT IN
子查询,因为该子查询基本上只是主查询的副本。
在那之后我看到的唯一大笔节省是
Listings.PriceCodeHeader.CustomerPriceLevelRecNbr IN (4,5)
任何类型的IN
或OR
通常都是尝试加快速度的好地方,因为精确匹配的处理速度往往要快得多。
将您的查询分成两个查询,一个与
Listings.PriceCodeHeader.CustomerPriceLevelRecNbr = 4
和其他的
Listings.PriceCodeHeader.CustomerPriceLevelRecNbr = 5
然后使用UNION ALL
组合查询结果也可能会提供一些改进。
之后,可能只有某个地方的索引丢失了。提供此优化查询的EXPLAIN
计划,我或许可以帮助确定另一个索引在哪里有用。
也就是说,在索引方面,您确实处于领先地位。大多数寻求查询优化帮助的人对索引的工作原理一无所知,但您是个例外。
【讨论】:
【参考方案2】: WHERE Listings.ItemListingHeader.MarketplaceRecNbr = 1
AND Listings.PriceCodeHeader.CustomerPriceLevelRecNbr IN (4, 5)
AND Listings.ItemListingHeader.RecNbr NOT IN ( SELECT ... )
将NOT IN
更改为LEFT JOIN ... IS NULL
WHERE
子句引用了多个表,无法添加跨多个表的索引。无论如何,在MarketplaceRecNbr
上有一个索引。 (稍后会更多。)在CustomerPriceLevelRecNbr
上。
您的索引存在一些效率低下的问题。研究这些规则:
PRIMARY KEY
是 UNIQUE
键是 INDEX
。 (参见`ItemListingHeader.RecNbr)
如果您有一个唯一键,其列是另一个唯一键的子集,则后者自动是唯一的,应将其更改为 INDEX
以避免额外的工作。
如果您也有相同的 beginning 列,则不需要INDEX(a,b)
:INDEX(a,b,c)
。您的情况更复杂,因为它涉及唯一性约束。 UNIQUE(a,b), UNIQUE(a,b,c)
--> UNIQUE(a,b), INDEX(b,a,c)
INDEX(a,b)
满足对 INDEX(a)
的任何需求,但它不满足 INDEX(b)
的需要。这就是订购问题。
根据这些规则,为每个表创建一组更好的索引。我会批评它。
【讨论】:
以上是关于有没有比多个子查询更好的方法来获得这个,也许有更多的连接?的主要内容,如果未能解决你的问题,请参考以下文章