1.7. Twin Project からのクエリー

1.7.1. 未分類の双子の検索
1.7.2. 双子のペアの状態を一覧にする

初期のMySQLが開発されていた地域 (Analytikerna and Lentus)で、ファウンダーたちは大規模研究 プロジェクトのシステム開発と実地調査を行っていました。 このプロジェクトは ストックホルムのカロリンスカ研究所の Institute of Environmental Medicine と 南カリフォルニア大学の Section on Clinical Research in Aging and Psychology との共同研究でした。

このプロジェクトはスウェーデンのすべての 65歳以上の双子のデータを 集めた大規模で複雑なものでした。 (http://ki.se/ki/jsp/polopoly.jsp?d=9610&l=en を参照)

プロジェクトの大部分は、Perl と MySQL によって記述された Web インターフェースで管理されています。

1.7.1. 未分類の双子の検索

次のクエリーは初期のスクリーニングの後にどの双子を 今後調査するかを決定するのに使用されます。 これは 1997 年に MySQL 3.19 で記述されたものです。

SELECT
    CONCAT(p1.id, p1.tvab) + 0 AS tvid,
    CONCAT(p1.christian_name, ' ', p1.surname) AS Name,
    p1.postal_code AS Code,
    p1.city AS City,
    pg.abrev AS Area,
    IF(td.participation = 'Aborted', 'A', ' ') AS A,
    p1.dead AS dead1,
    l.event AS event1,
    td.suspect AS tsuspect1,
    id.suspect AS isuspect1,
    td.severe AS tsevere1,
    id.severe AS isevere1,
    p2.dead AS dead2,
    l2.event AS event2,
    h2.nurse AS nurse2,
    h2.doctor AS doctor2,
    td2.suspect AS tsuspect2,
    id2.suspect AS isuspect2,
    td2.severe AS tsevere2,
    id2.severe AS isevere2,
    l.finish_date
FROM
    twin_project AS tp
    /* For Twin 1 */
    LEFT JOIN twin_data AS td ON tp.id = td.id
              AND tp.tvab = td.tvab
    LEFT JOIN informant_data AS id ON tp.id = id.id
              AND tp.tvab = id.tvab
    LEFT JOIN harmony AS h ON tp.id = h.id
              AND tp.tvab = h.tvab
    LEFT JOIN lentus AS l ON tp.id = l.id
              AND tp.tvab = l.tvab
    /* For Twin 2 */
    LEFT JOIN twin_data AS td2 ON p2.id = td2.id
              AND p2.tvab = td2.tvab
    LEFT JOIN informant_data AS id2 ON p2.id = id2.id
              AND p2.tvab = id2.tvab
    LEFT JOIN harmony AS h2 ON p2.id = h2.id
              AND p2.tvab = h2.tvab
    LEFT JOIN lentus AS l2 ON p2.id = l2.id
              AND p2.tvab = l2.tvab,
    person_data AS p1,
    person_data AS p2,
    postal_groups AS pg
WHERE
    /* p1 gets main twin and p2 gets his/her twin. */
    /* ptvab is a field inverted from tvab */
    p1.id = tp.id AND p1.tvab = tp.tvab AND
    p2.id = p1.id AND p2.ptvab = p1.tvab AND
    /* Just the screening survey */
    tp.survey_no = 5 AND
    /* Skip if partner died before 65 but allow emigration (dead=9) */
    (p2.dead = 0 OR p2.dead = 9 OR
     (p2.dead = 1 AND
      (p2.death_date = 0 OR
       (((TO_DAYS(p2.death_date) - TO_DAYS(p2.birthday)) / 365)
        >= 65))))
    AND
    (
    /* Twin is suspect */
    (td.future_contact = 'Yes' AND td.suspect = 2) OR
    /* Twin is suspect - Informant is Blessed */
    (td.future_contact = 'Yes' AND td.suspect = 1
                               AND id.suspect = 1) OR
    /* No twin - Informant is Blessed */
    (ISNULL(td.suspect) AND id.suspect = 1
                        AND id.future_contact = 'Yes') OR
    /* Twin broken off - Informant is Blessed */
    (td.participation = 'Aborted'
     AND id.suspect = 1 AND id.future_contact = 'Yes') OR
    /* Twin broken off - No inform - Have partner */
    (td.participation = 'Aborted' AND ISNULL(id.suspect)
                                  AND p2.dead = 0))
    AND
    l.event = 'Finished'
    /* Get at area code */
    AND SUBSTRING(p1.postal_code, 1, 2) = pg.code
    /* Not already distributed */
    AND (h.nurse IS NULL OR h.nurse=00 OR h.doctor=00)
    /* Has not refused or been aborted */
    AND NOT (h.status = 'Refused' OR h.status = 'Aborted'
    OR h.status = 'Died' OR h.status = 'Other')
ORDER BY
    tvid;

ちょっとだけ説明します:

  • CONCAT(p1.id, p1.tvab) + 0 AS tvid

    idtvab を結合したものを数値と見なして ソートしたいと思った。 結合結果の値に 0 を加えることで MySQL はその結果を数値として扱ってくれる。

  • id カラム

    これは双子の組を識別する。これは全てのテーブルの キーとなる。

  • tvab カラム

    これは双子のうちの一方を識別する。 12 のいずれかである。

  • ptvab カラム

    tvab の逆の値。 tvab1 の時にはこの値は 2 となる。 逆もまた真なり。 このカラムは、タイプ量を減らすためと、 MySQLがクエリーを最適化しやすいように設けられている。

このクエリーは特に、同一テーブルの結合 (p1p2) によってどのように検索を行えるのかを示しています。 この例では双子の相方が65歳より前に亡くなったか どうかをチェックするのに使われています。 相方が亡くなっている場合は、行は返ってきません。

上記すべては、双子情報のすべてのテーブル中に 存在しています。 id, tvab (すべてのテーブル)と id, ptvab(person_data) の両方のインデックスがあり、 クエリーを速くするのに役立っています。

我々がこの処理をする時、本番環境(200MHz UltraSPARC)の古いマシンで 約150–200 行を1秒以内で返します。 メインのテーブルには 70k 行あります。

1.7.2. 双子のペアの状態を一覧にする

双子のひとりひとりは event と呼ばれる 状態コードを持っています。 ここに示すクエリーは event によって紐づけられた双子の組 をすべて抽出するのに使われます。 これは どれだけの双子が両方とも調査完了したのか、 どれだけの双子が片方は調査完了しもう片方が拒否をしているのか などを示しています。

SELECT
        t1.event,
        t2.event,
        COUNT(*)
FROM
        lentus AS t1,
        lentus AS t2,
        twin_project AS tp
WHERE
        /* We are looking at one pair at a time */
        t1.id = tp.id
        AND t1.tvab=tp.tvab
        AND t1.id = t2.id
        /* Just the screening survey */
        AND tp.survey_no = 5
        /* This makes each pair only appear once */
        AND t1.tvab='1' AND t2.tvab='2'
GROUP BY
        t1.event, t2.event;