2007年11月03日

LIMITを使わないページング

前回はそもそも何をやりたかったのか?ということでLIMITを使ったページングの実装(前述した通り前者のタイプのページングは実装していましたが…詳細は前回参照)をしたい、というところまで書きましたが、今回はもう少し詳しく前者のLIMITを使わないページングについて説明したいとおもいます。

まずその前にデータベースの構造(テーブルスキーマ?というのか?わからん)とにかくRDBなのでテーブルがどうなっているかを説明しないと解りづらいとおもいますので、以下に…

前述したように平成の大合併で新たに誕生した新市町村と合併前の旧市町村のデータベースです。

TABLE newcity(新市町村)
id: integer primary auto_increment
pref_id: integer
city: varchar
yomi: varchar
gdate: date

TABLE oldcity(旧市町村)
id: integer primary auto_increment
city: varchar

TABLE joined(HABTM関連)
newcity_id: integer
oldcity_id: integer

TABLE pref(都道府県)
id: integer primary
name: varchar


本来はCREATE TABLEのSQLをそのまま書けばよいのでしょうが、そこは素人ってことで(^^;とりあえずこんな感じです。

メイン?のテーブルはnewcity(新市町村テーブル)でこれには新市町村の名前以外にその読みと合併日のフィールドも含まれています。pref_idは都道府県テーブルと単純に関連しているだけです。

oldcity(旧市町村テーブル)とはjoinedテーブルを介して、いわゆるhasAndBelongsToMany(略してHABTM?)と呼ばれる多対多の関連になっています。

と、さも当たり前のようにHABTMとか書いてますが、この構造?に到達するまでにどれだけ回り道をしたことか…、しかも最近知った言葉だし=>HABTM=はぶたむ???

とにかく階層構造?というか親子関係?というのか、なんかそんな感じのデータをRDBで表現するとこうするのがどうやら定石っぽいです。

で、このデータベースから検索結果を取得するわけですが、SQLを書く前に検索結果のイメージを…

search_result.png

見ての通り単純なテーブル(HTMLの)ですが、ポイントは新市町村1行に対して合併前の旧市町村が複数行で表示されてる、ってゆーか文章だと表現しづらいな、要するに<td rowspan="5">みたいな…とにかくそういうことです(--;

んでこれのいったいどこが問題なのか?

上記の画像はページング(DBから全件取得してスクリプトでページングするタイプ)が実装されていて、1ページあたり10件表示したところですが、問題なのは「10件」ってところで、見てのとおり新市町村が10件表示されているのがわかるとおもいます。

が!しかし!?

ここからが今回の核心なのですが、実はRDB上では、というかRDBから取ってきた結果上ではデータ件数は28件です。とおもってよくよく見るとなるほど旧市町村の数は28件あります。ふむふむってことは10件表示したい場合は28件データを取得しとけばいいってことだな…ナワケナイ

当然ですが2ページ目はまた違った件数(旧市町村の)になるわけなんですが、ここからは文章よりも実際のSQLとfetchの結果(の配列)を見てもらったほうが早いでしょう。

というわけでSQL…

SELECT pref.name pname, n.id nid, o.id oid, n.city nc, o.city oc, yomi, gdate FROM newcity n, oldcity o, joined j WHERE n.id = j.newcity_id AND o.id = j.oldcity_id AND pref.id = n.pref_id AND (検索条件 ※n.city like '%函館市%' など…)


JOINを使わないでWHERE句でテーブルを連結していますが、まあとりあえずどっちでもいいや…ってことで。そして配列に格納するところ…

foreach ($result as $row)
{
    $data[$row['nid']]['PREF'] = $row['pname'];
    $data[$row['nid']]['NCITY'] = $row['nc'];
    $data[$row['nid']]['OCITY'][$row['oid']] = $row['oc'];
    $data[$row['nid']]['BIRTH'] = $row['gdate'];
}


多少端折ってます。んでprint_rとか…

Array
(
[1] => Array
(
[PREF] => 北海道
[NCITY] => 函館市
[OCITY] => Array
(
[1] => 函館市
[2] => 戸井町
[3] => 恵山町
[4] => 南茅部町
[5] => 椴法華村
)
[BIRTH] => 2004-12-01
)

[2] => Array
(
[PREF] => 北海道
[NCITY] => 森町
[OCITY] => Array
(
[6] => 砂原町
[7] => 森町
)
[BIRTH] => 2005-04-01
)
:
:


と、こんな形の多次元配列に格納します。newcityのidをキーにすることで後は$dataの数を数えてゴニョゴニョやればページングの完了です。

$hits = count($data);
〜ごにょごにょ


前述した通り検索結果が数10件のうちはこれでもよいのでしょうが、100件あたりから怪しくなってきて、200件ぐらいでヤバイです。このテスト用のDBではそれほどではないかもしれませんが、本物の方はHABTMのリンクテーブルがもう一つあったため、200件の検索結果データから10件表示するだけで10秒以上かかった場合がありました(--;

そんなわけでLIMITの登場です。次回へ続く…
ラベル:PHP
posted by ciallost at 21:21| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック