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
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;
4

2 回答 2

1

有两件事会严重损害您的查询性能。

  1. 您通过组合多个条件来连接两个表,每个条件都需要子查询
  2. 您正在使用 SUBSTR(Zip,1,5)=SUBSTR(postalcode,1,5) 对两个表进行连接

您的查询背后的逻辑似乎是这样的:

对于每个 使用以下规则ECPs_Registration找到匹配记录:Rep_Codes

  • 如果 , 中存在匹配记录Reps_ShipTo,则用于该注册,使用该表查找(主要匹配)
  • 如果 中没有匹配的记录Reps_ShipTo,则通过Reps_ZipZipcode-match (secondary) 寻找匹配的 RepCode

现在,如果以上完全描述了您的情况,您可能应该从重新设计数据库开始。

该表在和Reps_ShipTo之间创建 0:N 关系。这样的关系不需要额外的表 - 它们可以简单地存储为可为空的外键 - 在您的情况下, a in可以解决问题,并且会从数据库中删除整个 Reps_ShipTo 表。ECPs_RegistrationRep_CodesRepCodeIdECPs_Registration

您可能还应该创建(是的,冗余的)额外列,仅将邮政编码的前 5 个字母存储在ECPs_Registration和中Reps_Zip。这将允许简单的相等匹配而不是 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

如果没有您的数据库架构和示例数据,我无法测试上述查询是否真的有效并且与您的原始结果相同。

于 2013-03-17T19:39:24.540 回答
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
于 2013-03-17T19:08:59.953 回答