我希望找到优化查询的最佳方法,如下所示:
SELECT
a.ID,
a.ECPCodeID,
a.RegDate,
a.BusName,
a.City,
a.AccountNum,
b.ID as RepCodeID,
b.RepCode
FROM ECPs_Registration a,
Reps_Codes b
WHERE (SUBSTR(a.PostalCode,1,5)IN(SELECT
SUBSTR(Zip,1,5)
FROM Reps_Zip
WHERE RepCodeID = b.ID)
AND a.AccountNum NOT IN(SELECT
ShipTo
FROM Reps_ShipTo))
OR a.AccountNum IN(SELECT
ShipTo
FROM Reps_ShipTo
WHERE RepCodeID = b.ID)
ORDER BY b.RepCode,a.BusName,a.City
我知道有更多因素涉及索引等等,我现在只是询问它的查询部分。主要是因为我必须通过Reps_ShipTo和Reps_Zip表来获取大量记录。我想改变像:
a.AccountNum NOT IN (SELECT ShipTo FROM Reps_ShipTo)
INTO
(SELECT count(*) FROM Reps_ShipTo WHERE a.AccountNum = ShipTo) = 0
不确定这是否正确或是否有更好的方法。任何帮助,将不胜感激。感谢。
编辑:
架构:
CREATE TABLE IF NOT EXISTS `ECPs_Codes` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`ECPCode` char(4) NOT NULL,
PRIMARY KEY (`ID`),
KEY `ECPCode` (`ECPCode`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE IF NOT EXISTS `ECPs_Registration` (
`RegDate` datetime NOT NULL,
`ID` int(10) NOT NULL AUTO_INCREMENT,
`ECPCodeID` int(11) NOT NULL,
`FirstName` varchar(200) NOT NULL,
`LastName` varchar(200) NOT NULL,
`BusName` varchar(200) NOT NULL,
`Address` varchar(200) NOT NULL,
`Address2` varchar(200) NOT NULL,
`City` varchar(100) NOT NULL,
`Province` char(2) NOT NULL,
`Country` varchar(100) NOT NULL,
`PostalCode` varchar(10) NOT NULL,
`Email` varchar(200) NOT NULL,
`AccountNum` int(8) NOT NULL,
PRIMARY KEY (`ID`),
KEY `ECPCodeID` (`ECPCodeID`),
KEY `PostalCode` (`PostalCode`),
KEY `AccountNum` (`AccountNum`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `Reps_Codes` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`RepCode` varchar(16) NOT NULL,
`AllAccess` tinyint(4) NOT NULL,
PRIMARY KEY (`ID`),
KEY `RepCode` (`RepCode`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `Reps_ShipTo` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`RepCodeID` int(11) NOT NULL,
`ShipTo` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`ID`),
KEY `RepID` (`RepCodeID`),
KEY `ShipTo` (`ShipTo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `Reps_Zip` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`RepCodeID` int(11) NOT NULL,
`Zip` varchar(10) NOT NULL,
PRIMARY KEY (`ID`),
KEY `RepCodeID` (`RepCodeID`),
KEY `Zip` (`Zip`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
答案 0 :(得分:1)
有两件事严重影响了您的查询效果。
您的查询背后的逻辑似乎是:
对于每个
ECPs_Registration
找到Rep_Codes
中的匹配记录 使用以下规则:
- 如果
Reps_ShipTo
中有匹配的记录,则对于该注册,请使用该表进行查找(主要匹配)- 如果
Reps_ShipTo
中没有匹配的记录,请通过邮政编码匹配(辅助)通过Reps_Zip
寻找匹配的RepCode
现在,如果以上内容完全描述了您的情况,您可能应该从重新设计数据库开始。
Reps_ShipTo
表在ECPs_Registration
和Rep_Codes
之间创建0:N关系。这样的关系不需要额外的表 - 它们可以简单地存储为可以为空的外键 - 在你的情况下RepCodeId
中的ECPs_Registration
可以做到这一点,并且会从数据库中删除整个Reps_ShipTo表
您还应该创建(是的,多余的)额外列,这些列仅存储ECPs_Registration
和Reps_Zip
中邮政编码的前5个字母。这将允许简单的相等匹配而不是SUBSTR函数。或者,您可能决定仅为每条记录执行此匹配一次,并将结果存储在上面RepCodeId
,完全取消双联接。
以下查询假定您由于某种原因不希望或无法更改数据库:
SELECT
a.ID, a.ECPCodeID, a.RegDate, a.BusName, a.City, a.AccountNum,
CASE (b1.ID IS NOT NULL, b1.ID, b2.ID) as RepCodeID,
CASE (b1.ID IS NOT NULL, b1.RepCode, b2.RepCode) as MyRepCode
FROM ECPs_Registration a
LEFT JOIN Reps_ShipTo ON (Reps_ShipTo.Shipto=a.AccountNum)
LEFT JOIN Rep_Codes b1 ON (b1.ID=Reps_ShipTo.RepCodeId)
LEFT JOIN Reps_Zip ON (SUBSTR(Zip,1,5)=SUBSTR(a.postalcode,1,5))
LEFT JOIN Rep_Codes b2 ON (b2.ID=Reps_Zip.RepCodeID)
ORDER BY MyRepCode,a.BusName,a.City
如果没有您的数据库架构和示例数据,我无法测试上述查询是否真正有效并且与原始查询具有相同的结果。
答案 1 :(得分:0)
SELECT
a.ID,
a.ECPCodeID,
a.RegDate,
a.BusName,
a.City,
a.AccountNum,
b.ID as RepCodeID,
b.RepCode
FROM ECPs_Registration a, Reps_Codes b
INNER JOIN Reps_Zip as r on SUBSTR(a.PostalCode,1,5) = SUBSTR(r.Zip,1,5)
LEFT JOIN Reps_ShipTo as rs on a.AccountNum = rs.ShipTo
LEFT JOIN ShipTo as s on a.AccountNum = s.ShipTo
WHERE (s.id is null or rs.id is null)
ORDER BY b.RepCode,a.BusName,a.City