3

姓、住所、性別、生年月日のフィールドを持つ 1200 万レコードの MyISAM テーブルを使用しています。

ID  SURNAME  GENDER       BDATE  COUNTY         ADDRESS         CITY
 1    JONES       M  1954-11-04     015       51 OAK ST  SPRINGFIELD
 2     HILL       M  1981-02-16     009     809 PALM DR   JONESVILLE
 3     HILL       F  1979-06-23     009     809 PALM DR   JONESVILLE
 4     HILL       F  1941-10-11     009     809 PALM DR   JONESVILLE
 5    SMITH       M  1914-07-27     035  1791 MAPLE AVE     MAYBERRY
 6    SMITH       F  1954-02-05     035  1791 MAPLE AVE     MAYBERRY
 7  STEVENS       M  1962-05-05     019  404 CYPRESS ST     MAYBERRY
 .        .       .           .       .               .
 .        .       .           .       .               .
 .        .       .           .       .               .

姓、日付、および住所フィールドは索引付けされます。私の目標は、次の基準で定義された推定婚姻状況のフィールドを追加することです: 各レコードについて、(1) 同一の姓、(2) 異なる性別、(3) 同一の住所を持つ別のレコードがテーブルに存在する場合、および (4) 年齢差が 15 歳未満の場合、既婚 = T と設定します。そうでなければ既婚に設定= F.

SQL の初心者である私の最初のアプローチは、デフォルトで 'F' に設定されている marital フィールドを追加し、次に自己結合を使用して MARRIED = T を設定することでした。

ALTER TABLE MY_TABLE
ADD COLUMN MARRIED CHAR(1) NOT NULL DEFAULT 'F';

UPDATE MY_TABLE T1, MY_TABLE T2
SET T1.MARRIED = 'T' WHERE
  T1.SURNAME = T2.SURNAME AND
  T1.GENDER != T2.GENDER AND
  T1.ADDRESS = T2.ADDRESS AND
  T1.CITY    = T2.CITY AND
  ABS(YEAR(T1.BDATE)-YEAR(T2.BDATE)) < 15;

これは小さなテーブルでは問題なく機能しますが、1,200 万行のテーブルでこのプロセスが完了する前に引退する可能性が高いことがすぐにわかりました。私の SQL の知識は非常に限られているため、これは次善のアプローチであると確信しています。提案された代替案はありますか?おそらくSURNAME + ADDRESS + CITYの索引付けですか?最初に ADDRESS + CITY でグループ化しますか? より良いテーブルデザイン? 任意の提案をいただければ幸いです。

助けてくれてありがとう!

4

3 に答える 3

1

兄弟姉妹に気をつけろ!

于 2010-08-28T17:37:57.390 に答える
1

いくつかのバリエーションを試して、どれが最高のパフォーマンスを発揮するかを確認します。

単純なExistsを使用しているが、ABS値関数の代わりにDate_Addを使用しているバージョン1:

Update My_Table
Set Married = 'T'
Where Exists    (
                Select 1
                From My_Table As T2
                Where T2.SurName = My_Table.SurName
                    And T2.Gender != My_Table.Gender
                    And T2.Address = My_Table.Address
                    And T2.City = My_Table.City
                    And (
                        T2.BDate > Date_Add(My_Date.BDate, Interval 15 Year)
                        Or T2.BDate < Date_Add(My_Date.BDate, Interval -15 Year)
                        )
                )

UNIONALLを使用したバージョン2

Update My_Table
Set Married = 'T'
Where Exists    (
                Select 1
                From My_Table As T2
                Where T2.SurName = My_Table.SurName
                    And T2.Gender != My_Table.Gender
                    And T2.Address = My_Table.Address
                    And T2.City = My_Table.City
                    And T2.BDate > Date_Add(My_Date.BDate, Interval 15 Year)
                Union All
                Select 1
                From My_Table As T2
                Where T2.SurName = My_Table.SurName
                    And T2.Gender != My_Table.Gender
                    And T2.Address = My_Table.Address
                    And T2.City = My_Table.City
                    And T2.BDate < Date_Add(My_Date.BDate, Interval -15 Year
                )

内部結合とDate_Addを使用するバージョン3

Update My_Table As T1
    Join My_Table As T2
            On T2.SurName = T1.SurName
                And T2.Gender != T1.Gender
                And T2.Address = T1.Address
                And T2.City = T1.City
Set Married = 'T'
Where T1.BDate > Date_Add(T2.BDate, Interval 15 Year)
        Or T1.BDate < Date_Add(T2.BDate, Interval -15 Year)

SQLから離れて、提供された情報に基づいて2人が結婚しているかどうかを推測しようとすると、問題が発生するだろうと思います。15歳よりも年齢差が大きいカップル(アンナニコルスミスは誰ですか?)も、兄弟も、結婚しても名前を変更しない2人は考慮されません。

于 2010-08-28T17:39:38.520 に答える
0

さて、WHERE句のすべてのフィールドにインデックスを付けると、クエリが確実に高速化されます。

これは、SURNAME、GENDER、ADDRESS、CITY、およびBDATEを意味します。

もう1つ試すことができるのは、ON部分の結果を絞り込むためのルールを定義することです。

UPDATE MY_TABLE T1
  LEFT JOIN MY_TABLE T2
  ON T1.SURNAME = T2.SURNAME
    AND T1.GENDER != T2.GENDER
    AND T1.CITY   = T2.CITY
  SET T1.MARRIED = 'T'
  WHERE ABS(YEAR(T1.BDATE)-YEAR(T2.BDATE)) < 15;
于 2010-08-28T17:06:15.473 に答える