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

クエリのパフォーマンスを大幅に低下させるものが2つあります。

  1. 複数の条件を組み合わせて2つのテーブルを結合し、それぞれにサブクエリが必要です
  2. SUBSTR(Zip、1,5)= SUBSTR(postalcode、1,5)を使用して2つのテーブルで結合を行っています

クエリの背後にあるロジックは次のようになります。

次のルールを使用してECPs_Registration、一致するレコードをすべて検索します。Rep_Codes

  • に一致するレコードがある場合Reps_ShipTo、その登録については、そのテーブルを使用して検索します(プライマリ一致)
  • に一致するレコードがない場合は、Zipcode-match(secondary)で一致するRepCodeをReps_ShipTo探します。Reps_Zip

上記で状況が完全に説明されている場合は、データベースを再設計することから始める必要があります。

このテーブルは、との間にReps_ShipTo0:Nの関係を作成します。このような関係には追加のテーブルは必要ありません。null許容の外部キーとして保存できます。この場合、inがトリックを実行し、Reps_ShipToテーブル全体をデータベースから削除します。ECPs_RegistrationRep_CodesRepCodeIdECPs_Registration

おそらく、との両方に郵便番号の最初の5文字のみを格納する(はい、冗長な)追加の列を作成する必要がありECPs_RegistrationますReps_Zip。これにより、SUBSTR関数の代わりに単純な等式一致が可能になります。または、この一致をレコードごとに1回だけ実行し、結果を上記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 に答える