初期の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 インターフェースで管理されています。
次のクエリーは初期のスクリーニングの後にどの双子を 今後調査するかを決定するのに使用されます。 これは 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
id と
tvab を結合したものを数値と見なして
ソートしたいと思った。
結合結果の値に 0 を加えることで
MySQL はその結果を数値として扱ってくれる。
id カラム
これは双子の組を識別する。これは全てのテーブルの キーとなる。
tvab カラム
これは双子のうちの一方を識別する。
1 か 2
のいずれかである。
ptvab カラム
tvab の逆の値。
tvab が 1
の時にはこの値は 2 となる。
逆もまた真なり。
このカラムは、タイプ量を減らすためと、
MySQLがクエリーを最適化しやすいように設けられている。
このクエリーは特に、同一テーブルの結合
(p1 と p2)
によってどのように検索を行えるのかを示しています。
この例では双子の相方が65歳より前に亡くなったか
どうかをチェックするのに使われています。
相方が亡くなっている場合は、行は返ってきません。
上記すべては、双子情報のすべてのテーブル中に
存在しています。
id, tvab (すべてのテーブル)と
id, ptvab(person_data)
の両方のインデックスがあり、
クエリーを速くするのに役立っています。
我々がこの処理をする時、本番環境(200MHz UltraSPARC)の古いマシンで 約150–200 行を1秒以内で返します。 メインのテーブルには 70k 行あります。
双子のひとりひとりは 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;