奇特なブログ

「殊勝に値する行いや心掛け」を意味する、奇特な人になる為のブログです

手続き型的に学ぶEXISTS述語の基本

3月頃から、SQL ゼロからはじめるデータベース操作を読んでいたのですが、
1箇所大ハマリした所があったので、その復習も兼ねて。
で、参考になる人もいらっしゃるかもしれないのでブログに書きます。

プログラミングをやっている手続き型に慣れた人にとって、
SQLのEXISTSって馴染みづらくないですかね?
少なくともウチはそうなんですけど。
なので今回は、EXISTSの挙動をイメージ出来る様になる為に、
「おそらく内部挙動はこうなっているのではないか」と予測したプログラムを書いてみました。
合っているかどうかは分からないですけどね。

では、本題に入りますが、
まず、以下の様なデータが入っている2つのテーブルを作成しました。
参考までに、ウチのDB環境はMySQL5.5.16です。

商品一覧テーブル

商品名
テレビ
パソコン
携帯電話

会員テーブル

会員ID 購入商品名
1 テレビ
1 パソコン
1 携帯電話
1 洗濯機
2 テレビ
2 パソコン
2 携帯電話
3 パソコン
3 テレビ
3 冷蔵庫
3 電子レンジ
3 DVDレコーダー
4 電子レンジ
5 テレビ

まずは、簡単なEXISTSから書くことにします。
まずは、以下のSQLについて。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

SQL文

select
 *
from
 会員テーブル A
where
 exists
  (select
   *
  from
   商品一覧テーブル B
  where
   A.購入商品名 = B.商品名
  );

結果(赤くなっている行が表示される行です)

会員ID 購入商品名
1 テレビ
1 パソコン
1 携帯電話
1 洗濯機
2 テレビ
2 パソコン
2 携帯電話
3 パソコン
3 テレビ
3 冷蔵庫
3 電子レンジ
3 DVDレコーダー
4 電子レンジ
5 テレビ

プログラム
<?php

$arr1 = array(
          array(1,'テレビ'),
	  array(1,'パソコン'),
	  array(1,'携帯電話'),
	  array(1,'洗濯機'),
	  array(2,'テレビ'),
	  array(2,'パソコン'),
	  array(2,'携帯電話'),
	  array(3,'パソコン'),
	  array(3,'テレビ'),
	  array(3,'冷蔵庫'),
	  array(3,'電子レンジ'),
	  array(3,'DVDレコーダー'),
	  array(4,'電子レンジ'),
	  array(5,'テレビ')
	);

$arr2 = array('テレビ','パソコン','携帯電話');

$view_arr = array();

// 会員テーブルの行を1行ずつ見ていく
for ($i = 0; $i < count($arr1); $i++) {
  // 会員テーブルの商品名が、商品一覧テーブルに含まれているか
  if (true === in_array($arr1[$i][1], $arr2)) {
    // 含まれて「いる」場合は、表示対象行となる
    $view_arr[] = $arr1[$i];
  }
}

for ($i = 0; $i < count($view_arr); $i++) {
  for ($j = 0; $j < count($view_arr[$i]); $j++) {
    echo $view_arr[$i][$j] . ',';
  }
  echo "\r\n";
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------

さて、上記のSQLを紐解いてみますと。
これは、「会員テーブルの購入商品名が、商品一覧テーブルに存在するかどうかを調べ、
存在する行のみを表示する」というSQLです。
「A.購入商品名 = B.商品名」の所で、商品が存在するかをチェックしています。
で、上記の場合だと、サブクエリのSQL(EXISTSの「内」側のSQL)でヒットする行が赤文字になっている行で、
その行をそのまま表示しています。
つまりEXISTSの基本は、「サブクエリでヒットした行をそのまま表示する」ということになります。
勿論、サブクエリじゃない方のSQL(EXISTSの「外」側のSQL)にwhere句とかがあれば、
更に表示する行は絞りこまれますけど。

次は、上記の逆で「NOT」を使ってみます。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

SQL文

select
 *
from
 会員テーブル A
where
 not exists
  (select
   *
  from
   商品一覧テーブル B
  where
   A.購入商品名 = B.商品名
  );

結果(赤くなっている行が表示される行です)

会員ID 購入商品名
1 テレビ
1 パソコン
1 携帯電話
1 洗濯機
2 テレビ
2 パソコン
2 携帯電話
3 パソコン
3 テレビ
3 冷蔵庫
3 電子レンジ
3 DVDレコーダー
4 電子レンジ
5 テレビ

プログラム
<?php

$arr1 = array(
	  array(1,'テレビ'),
	  array(1,'パソコン'),
	  array(1,'携帯電話'),
	  array(1,'洗濯機'),
	  array(2,'テレビ'),
	  array(2,'パソコン'),
	  array(2,'携帯電話'),
	  array(3,'パソコン'),
	  array(3,'テレビ'),
	  array(3,'冷蔵庫'),
	  array(3,'電子レンジ'),
	  array(3,'DVDレコーダー'),
	  array(4,'電子レンジ'),
	  array(5,'テレビ')
	);

$arr2 = array('テレビ','パソコン','携帯電話');

$view_arr = array();

// 会員テーブルの行を1行ずつ見ていく
for ($i = 0; $i < count($arr1); $i++) {
  // 会員テーブルの商品名が、商品一覧テーブルに含まれていないか
  if (false === in_array($arr1[$i][1], $arr2)) {
    // 含まれて「いない」場合は、表示対象行となる
    $view_arr[] = $arr1[$i];
  }
}

for ($i = 0; $i < count($view_arr); $i++) {
  for ($j = 0; $j < count($view_arr[$i]); $j++) {
    echo $view_arr[$i][$j] . ',';
  }
  echo "\r\n";
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------

「NOT」を付けなかった時とは、全く逆の結果になったって当たり前ですけど。
じゃあ、SQLを紐解いてみると。
サブクエリを実行した時点での結果は、上記2つで差異はないのですが、
「NOT」の場合は、サブクエリのSQLでヒット「しない」行を表示します。
つまりNOT EXISTSの基本は、「サブクエリでヒット"しない"行をそのまま表示する」ということになります。
こうやって書くと至って単純なんですけどねぇ。

じゃあ次は、EXISTSを入れ子にしてみます。
サブクエリを示す括弧に色を着けたのにも注意です。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

SQL文

select
 *
from
 会員テーブル A1
where
 exists
  (select
   *
  from
   商品一覧テーブル B
  where
   exists
    (select
     *
    from
     会員テーブル A2
    where
     A1.会員ID = A2.会員ID and
     B.商品名 = A2.購入商品名
    )
  );

結果(赤くなっている行が表示される行です)

会員ID 購入商品名
1 テレビ
1 パソコン
1 携帯電話
1 洗濯機
2 テレビ
2 パソコン
2 携帯電話
3 パソコン
3 テレビ
3 冷蔵庫
3 電子レンジ
3 DVDレコーダー
4 電子レンジ
5 テレビ

プログラム
<?php

$arr1 = array(
	  array(1,'テレビ'),
	  array(1,'パソコン'),
	  array(1,'携帯電話'),
	  array(1,'洗濯機'),
	  array(2,'テレビ'),
	  array(2,'パソコン'),
	  array(2,'携帯電話'),
	  array(3,'パソコン'),
	  array(3,'テレビ'),
	  array(3,'冷蔵庫'),
	  array(3,'電子レンジ'),
	  array(3,'DVDレコーダー'),
	  array(4,'電子レンジ'),
	  array(5,'テレビ')
	);

$arr2 = array('テレビ','パソコン','携帯電話');

$view_arr = array();

// 会員テーブルAの行を1行ずつ見ていく
for ($i = 0; $i < count($arr1); $i++) {
  // 商品一覧テーブルの行を1行ずつ見ていく
  for ($j = 0; $j < count($arr2); $j++) {	
    // 会員テーブルBの行を1行ずつ見ていく
    for ($k = 0; $k < count($arr1); $k++) {
      // 会員テーブルの会員IDが同じものの中で商品を比較したいので
      // 会員テーブルの会員IDが同じかどうかチェックする
      if ($arr1[$i][0] === $arr1[$k][0]) {
	// 同じ会員IDの中で、商品名が一致するか
	if (true === in_array($arr2[$j], $arr1[$k])) {
	  // 含まれて「いる」なら表示対象行とし、会員テーブルAの参照行を次の行にする
	  /* 同じ会員IDの中で、商品名が1行でも一致していたら、
	  その会員IDの全ての行が表示対象行となる */
	  $view_arr[] = $arr1[$i];
	  $k = count($arr1);
	  $j = count($arr2);
	}
      }
    }
  }
}

for ($i = 0; $i < count($view_arr); $i++) {
  for ($j = 0; $j < count($view_arr[$i]); $j++) {
    echo $view_arr[$i][$j] . ',';
  }
  echo "\r\n";
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------

これは、「会員ID毎に、購入商品が商品一覧に存在するかどうかを調べ、
存在する場合は、その会員IDと同じ会員IDの行を全て表示する」SQLです。
逆に言えば、同じ会員ID内で一行でも商品一覧に存在する購入商品があれば、
存在する行の会員IDと同じ会員IDの行も表示されるって事ですね。
と、ここまでは良いんですが、ただプログラムの方が微妙な感じが(苦笑)
何となくですけど、こういう内部挙動では無い気がするんですよね。

と、段々分からなくなってきたんですが、
最後に一応、NOT EXISTSの入れ子を掲載しておきます。
上記の書籍でハマったのはコレでした。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

SQL文

select
 *
from
 会員テーブル A1
where
 not exists
  (select
   *
  from
   商品一覧テーブル B
  where
   not exists
    (select
     *
    from
     会員テーブル A2
    where
     A1.会員ID = A2.会員ID and
     B.商品名 = A2.購入商品名
    )
  );

結果(赤くなっている行が表示される行です)

会員ID 購入商品名
1 テレビ
1 パソコン
1 携帯電話
1 洗濯機
2 テレビ
2 パソコン
2 携帯電話
3 パソコン
3 テレビ
3 冷蔵庫
3 電子レンジ
3 DVDレコーダー
4 電子レンジ
5 テレビ

プログラム
<?php

$arr1 = array(
	  array(1,'テレビ'),
	  array(1,'パソコン'),
	  array(1,'携帯電話'),
	  array(1,'洗濯機'),
	  array(2,'テレビ'),
	  array(2,'パソコン'),
	  array(2,'携帯電話'),
	  array(3,'パソコン'),
	  array(3,'テレビ'),
	  array(3,'冷蔵庫'),
	  array(3,'電子レンジ'),
	  array(3,'DVDレコーダー'),
	  array(4,'電子レンジ'),
	  array(5,'テレビ')
	);

$arr2 = array('テレビ','パソコン','携帯電話');

$view_arr = array();

$str = '';

// 会員テーブルAの行を1行ずつ見ていく
for ($i = 0; $i < count($arr1); $i++) {
  // 商品名一致カウンター
  $hits = 0;
  // 商品一覧テーブルの行を1行ずつ見ていく
  for ($j = 0; $j < count($arr2); $j++) {
    // 会員テーブルBの行を1行ずつ見ていく
    for ($k = 0; $k < count($arr1); $k++) {
      // 会員テーブルの会員IDが同じものの中で商品を比較したいので
      // 会員テーブルの会員IDが同じかどうかチェックする
      if ($arr1[$i][0] === $arr1[$k][0]) {
	// 同じ会員IDの中で、商品名が一致するかどうかをチェック
	if (true === in_array($arr2[$j], $arr1[$k])) {
	  // 商品名が同じなら商品名一致カウンターを増やし、商品一覧テーブルの参照行を次の行にする
	  $hits++;
	  break;
	}
      }
    }
    // 商品名一致カウンターと商品一覧テーブルの商品数が同じかどうかチェックする
    if ($hits === count($arr2)) {
      // 同じ場合は、商品一覧テーブル内の商品が全て含まれているので、表示対象行とする
      $view_arr[] = $arr1[$i];
    }
  }
}

for ($i = 0; $i < count($view_arr); $i++) {
  for ($j = 0; $j < count($view_arr[$i]); $j++) {
    echo $view_arr[$i][$j] . ',';
  }
  echo "\r\n";
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------

一応、NOT EXISTSの入れ子のSQLにも触れておくと、
「商品一覧テーブルに存在する"全て"の商品を購入した人を表示するSQL」です。
プログラムはもう、メチャクチャですね(苦笑)
単に、SQL実行結果に合わせてプログラムを書いただけみたいなモンです。

まぁ、今後の課題ということで、今回はここまでにします。
もうちょっと「集合論」というものを、勉強する必要がある様に感じました。

テーマ:日記 - ジャンル:日記

  1. 2012/05/06(日) 19:32:50|
  2. データベース
  3. | トラックバック:0
  4. | コメント:0

SIは今後どうなっていくか

今回は、単なる雑感をダラダラと書いてみます。
元ネタはコチラ。

SI屋さんとSIと、直近の課題について。
http://d.hatena.ne.jp/okachimachiorz/20120311/1331467375
一旦大きな人数を抱えると、食わせる必要があるため、より大きな仕事を取る羽目になります。要は稼働させる事、それ自体が目的になります。稼働を維持させる事で、収入を確保する事ができ、確保された収入で稼働のための人員を維持できる。そもそもそういう循環をベースに組織の目的が、「結果として」形成されてしまっています。
そうですねぇ。
稼働してなかったら「待機」となって、毎月ウン十万の会社に入っていたお金が入らなくなるわけですから。
で、そのお金が入らなくなったら、
新たに人材を確保する為の採用費用(広告費とか)や、
会社の間接部門(営業や事務など)への給料や、
会社のサーバーなどの設備増強費用などが払えなくなってしまいます。
勿論、待機になった人材自身の給料も。
まぁその場合は、他の現場に入っている人材が上げた利益から払うしかないと思いますが。
とはいえ、現場に入っている人材の数が少なくなるとそうもいかなくなるので、
とにかく、「待機にさせないで現場に入れる」が最優先になってしまうでしょう。
副作用として、この時点で、どうしても顧客視点は薄くなります。稼働率優先になると、どういう価値を顧客に届けるとか?という視点が、特にマネージメントでは相対的に優先度は低くなります。これ現状では仕方のないことでしょう。良いとか悪いとか、そういう議論ではなく、組織の合目的性の維持が根っこにありますよ、という話です。
「組織の合目的性の維持」。
つまり、会社は何がなんでも潰すわけにはいかないから、
顧客価値などというカッコイイ事はどうでも良いから、とにかく現場に入れと。
現状のマネジメント層の殆どをウチが見ている限りでは。
勿論口には出しませんし、本心からは思ってもいないとは思うのですが、
こんな風に思っているんじゃないかとしか思えない現状だと思いますがね(苦笑)
特に基幹系のシステムは基本的にパッケージカスタマイズには向きません。よほどのニッチ・トップをめざした業務系パッケージならともかく、ありきたりのERP系の仕組みではまったく対応できません。理由は種々にあるので、詳細な議論は別の機会に譲るとして、結果から言うと、(これが惰性なのか、ちゃんとした検討の結果なのかはともかく、)現行のパッケージでは相当のカスタマイズが発生することが多いです。個人的な経験的にいうと、パッケージを作っている人間に業務経験が少ないというのが最大の理由だと思っています。
業務経験が少ない、なるほど。
あと、それもあるかもしれませんが、単純に顧客固有の独自仕様が多いというのもあるんじゃないですかね。
よく言われるITの35歳定年説は、見たところ体力的なものです。これは、すなわち、SIで使い倒せる体力がある年齢の上限が35歳であって、技術的な吸収力ではないと思います。(吸収力は基礎勉強性向によるので、年齢は関係ないです。)仮にこの35歳以下の年齢層が半分にもなれば、すなわち、従来のピラミッド構築型のSIはまったく回らなくなります。“労働人口構造的”にです。
ウチ的には、35歳という数値自体には特に大きな意味はないと思っていまして、
今は上記の労働人口構造的に、40歳ぐらいに上がってきているんじゃないかという感じがしています。
だからこの先は、まったく回らなくなっていくというよりは、
次は45歳とかどんどん上限が上がっていくんじゃないかなぁと。
まぁ、その結果として、どんな品質のシステムが作られるかはともかくとして(苦笑)
また、「吸収力は基礎勉強性向によるので、年齢は関係ない」については完全に同意です。
ここ4−5年のSIの失敗率は、個人的に見ている限りは異常と言わざるを得ません。人員の確保ができないため、もう猿だか、猫だかわからないような人員ですらSIの現場に突っ込まれていることが日常茶飯事になっています。というか、そうでない現場の方が少ないように思えます。
ウチ的には、ソフトウェア開発で最も差が出るのは「品質」だと思っているんですが。
例えば、ココの分類でいうと、
レベル3どころか、レベル2にすら満たないケースも多く。
また、レベル1もそう珍しくない感じで。
技術者によっては、レベル1未満なケースも時々見かけます orz
ウチが現在、業界歴3年生なので、
4〜5年前以前の品質がどんな感じだったのかが分からないのですが。
少なくても、ウチが現在行っている現場の品質は、上記の様な感じですって終わってるじゃねぇか orz
特に現場から距離のある経営陣や部長以上の経営的中間管理職には、どうしても、その意識が薄くなってしまうということです。こと最近でいうと、クラウドやなんやらで、SIはどうかわるかという議論は、情報誌・雑誌・果てはイベントや、その手の座談会で良く聞きますが、下支えのSIの産業構造の崩壊に対する自覚はまったくないのは、よく観察されるところです。
ですねぇ、ですねぇ、ですねぇ。
下請けSIの経営・管理系や情報収集力の乏しい現場の人間は、
こんな実情は全く知らないと思います。
まぁ彼ら的には、諸行「有」常なのでしょう(苦笑)
偉い人「代わりはいないのか?」
PM「居ませんよ。」
偉い人「いや、エースの代わりじゃなくて、普通でいいんだけど。
設計出来て、そこそこ実装できて、普通にテストかければいい。
インフラはもう知らなくてもいいから」
PM「・・・それエースって言うんですよ。知ってます?」
偉い人「まじで?」
PM「まじで。」
偉い人「いないの?」
PM「絶無・皆無(目線は遠くへ。かなり遠く。」

...これが現実ですね。クラウドでSIが変わる?いや変わるべきSIがもう成立していません。
居ないですねぇ、エース。
優秀な人材は、Web業界に行ってしまったとかも関係あるんでしょうかね?
いや、そもそも本当に、優秀な人材がWeb業界に行ったかどうかが分からないのですが。
さすがに、ゼロではないとは思いますけど。
かっちりモノをつくるという風潮が駄目よ、という流れも加速していることです。本来アジャイルや、Web系、Rubyを含めたLL系・スクリプト系は、勝手気ままに思いつきで作るということとは違うはずです。残念ながら同じコンテクストになってしまっていますね。
実は、ココが一番興味があったんですが。
これは、「ウォーターフォールなんて時代遅れだ!これからはアジャイルだ!」みたく言うエンジニアもどきが、
アジャイルの上っ面だけを知ったかぶりして、
ロクに要件や設計を考えないで実装した結果、
普通にウォーターフォールで作った時「よりも」、品質が「下がってしまう」というケースの事ですかね?
アジャイルでは無かったですが、
過去に「理解不足のまま新技術を導入」して、
結果として大失敗は防げたものの、
結構デスマーチになったPJがありましたので(苦笑)
ここは、まだ検証不足ではありますが、
多分、中途半端な理解でアジャイルをするよりは、
まだウォーターフォールの方が品質はマシになるんじゃないかなぁと、ボンヤリと思ってます。
だって、アジャイルの方が難しいと思いますし。
勿論、ウォーターフォールだと。
プロジェクト開始前に「水も漏らさぬ完璧な要求」と、
「変更などあり得ない完全な仕様」が存在している事が前提にはなり、
それはビジネスの流れに合わせられない事が多いという課題はあるわけですけど。
昔のリソース制限化では、自然にハードウェアの制限がかかって、無茶はできず、大崩壊する前に歯止めがかかったのですが、現在では「多少無茶でも動いてしまう」ということがあるため、とりあえずやっつけろ!という方向に走りがちです。設計していないのに実装するとか、普通に考えればないはずなのですが、普通にあります。
う〜ん、まぁ確かにハードの進化が止まらないが「故に」、
メモリ使用量とかに配慮したコードが書けなくなってきている部分も大きそうですね。
そういえば、先日ウチが書いた値渡しと参照渡しの速度比較の内容も、
結局メモリの使い方に問題があって起きる事象でしたし。
稼働率優先のビジネスをまずは完全にギブアップする。これは相当ハードルが高いです。少数の人間でも一定のSIが回る仕組みを構築し、同時に相当な額の一時的な(あるいは恒久的な)売上減を前提とした上で全体の計画を立て直して、人繰りに依存しない組織立て、道具立てを準備していく必要があります。
まぁ、これを真面目に実践すると、
少なくても80%以上のシステム会社やその中の人達は、全員さようならになると思いますけど。
だって、「少数の人間でも一定のSIが回る仕組み」って、
その人間達のスキルが高くないと出来ないでしょ。
じゃあ、そうする為には教育を施す必要があると思いますが、
まず、まともに教えられる人がいるのかという問題と、
また、教わる人々がちゃんと取り組むのかという問題があると思います。
で、現状を見るに・・・どっちも期待出来ないんじゃないかと(苦笑)
SI屋が自壊することで、困るのはむしろSI屋ではなく、適切なSIが提供されないことにより、あたかもメンテ不能な原発のような、システムを抱えるエンドユーザーさんになります。
未来を予想するのは難しいですけど、
ウチは何だかんだいっても、
エンドユーザーさんが優秀な技術者を自社に囲い込む可能性が高いと思いますね。
もしくは、極めて少数の優秀なSlerに仕事を依頼するか。
勿論お金はかかるけれども、メンテ不能なシステムを抱え込むよりは、
金額的に比較は出来ませんが、メリットは大きくはないのですかね。
で一方で、何も舵を取らないエンドユーザーさんは、
ここまで書いてきたようなダメダメSlerに仕事を依頼し続け、
増々ダメになっていくという二極化が進むのではないかと。

雑感はここまでで、最後にじゃあ今Slerに所属している技術者達はどうすれば良いのかですが、
ありきたりですが、「基礎力がある為、応用の利く、替えの利きにくい技術者になればよい」と思います。
で、その為には、新しい技術だけでなく古い技術も学んで基礎力を付けたり、
師匠(メンター)を探して、効率的に学習するしかないのではないでしょうかね。

テーマ:日記 - ジャンル:日記

  1. 2012/03/27(火) 23:40:01|
  2. IT
  3. | トラックバック:0
  4. | コメント:0

未購入本の一覧

ちょっと更新が空いていたので、こんな記事で埋めてみますw
んで、この記事の書いた目的は。
元々自分の携帯のお気に入りに、
未読だけど興味ある本を登録していたんですけど、
多分そろそろ登録し切れなくなる(以前の携帯で発生しました)ので、
ここに書いて管理しましょうかと。
だから、完全にウチ専用w
まぁ、もしかしたら誰かの参考にはなるかもしれませんけど。
でも以下の一覧は、ウチが本を買った or 買わないと判断した瞬間に「その行は削除します」のでご注意下さい。
しっかしまぁ、まずは自宅の積ん読状態をどうにかするのが先なんですけどね(苦笑)

書籍名(リンク先はアマゾンの書籍ページ) 備考
Making Software ―エビデンスが変えるソフトウェア開発 多分買う
「甘え」の構造 [増補普及版] 買わないかも
コンサルティングとは何か 買うかな?
求心力―人を動かす10の鉄則 買うかな?
死ぬほど大切な仕事ってなんですか―リストラ・職場いじめ時代に過労死を考える 買うかな?
ソーシャルゲームはなぜハマるのか ゲーミフィケーションが変える顧客満足 買わないかも
部下を育てる「ものの言い方」 ―人を変える組織を変えるリーダー必須の条件 買わないかも
理系の人々 買うかな?
情報社会と共同規制: インターネット政策の国際比較制度研究 買うかな?
セブン‐イレブンの正体 買わないかも
プレイングマネジャーの教科書―結果を出すためのビジネス・コミュニケーション58の具体策 買わないかも
プレイング・マネジャー―現場と管理職を兼任する人のためのコーチング術 買わないかも
「新・ぶら下がり社員」症候群 買わないかも
采配 多分買う
リレーショナルデータベース入門―データモデル・SQL・管理システム 多分買う
データベース実践講義 ―エンジニアのためのリレーショナル理論 絶対買うけどまだ早い
ビジネスパーソンのための契約の教科書 買うかな?
不夜城 多分買う
つながり 社会的ネットワークの驚くべき力 多分買う
ノンデザイナーズ・デザインブック [フルカラー新装増補版] 多分買う
論より詭弁 反論理的思考のすすめ 買うかな?
論理で人をだます法 買うかな?
レトリックと詭弁 禁断の議論術講座 買うかな?
大局観 自分と闘って負けない心 買うかな?
リーダーシップ―胆力と大局観 買うかな?
珠玉のプログラミング―本質を見抜いたアルゴリズムとデータ構造 多分買うけどまだ早い
最後に思わずYESと言わせる最強の交渉術―かけひきで絶対負けない実戦テクニック72 売ってねぇ〜
ヤクザの実戦心理術―なぜ彼らの言いなりになってしまうのか 買うかな?
20歳のときに知っておきたかったこと スタンフォード大学集中講義 買うかな?
中国化する日本 日中「文明の衝突」一千年史 買わないかも
「上から目線」の時代 多分買わない
伝える力 多分買う
「見せかけの勤勉」の正体 買わないかも
モチベーション3.0 持続する「やる気!」をいかに引き出すか 買うかな?
数学ガール 絶対買うがまだ理解出来ないのでは?
日本語入力を支える技術 ~変わり続けるコンピュータと言葉の世界 買わないかも
100人のプロが選んだソフトウェア開発の名著 君のために選んだ1冊 買わないかも
バリュープロポジション戦略50の作法 - 顧客中心主義を徹底し、本当のご満足を提供するために 多分買う
論語 (岩波文庫) 多分買う
経済学及び課税の原理 (名著/古典籍文庫―岩波文庫復刻版) 買うかな?
五体不満足 完全版 (講談社文庫) 多分買う
ロジカル・シンキング―論理的な思考と構成のスキル 多分買う
非言語(ノンバーバル)コミュニケーション (新潮選書) 買うかな?
アイデアのつくり方 買うかな?
閉じこもるインターネット――グーグル・パーソナライズ・民主主義 買うかな?
詳説 正規表現 第3版 買うかな?
エバンジェリスト養成講座 究極のプレゼンハック100 買うかな?
マネーの虎 買うかな?
思考の整理学 (ちくま文庫) 買うかな?
プロフェッショナルたちの脳活用法 多分買う
リファクタリング―プログラムの体質改善テクニック 買うかな?
リファクタリング・ウェットウェア ―達人プログラマーの思考法と学習法 絶対買う
[24時間365日] サーバ/インフラを支える技術 ~スケーラビリティ、ハイパフォーマンス、省力運用 多分買う
[Web開発者のための]大規模サービス技術入門 ―データ構造、メモリ、OS、DB、サーバ/インフラ 多分買う
インターネットの法律Q&A―これだけは知っておきたいウェブ安全対策 買うかな?
言いにくいことをうまく伝える会話術 買うかな?
決定版 ハーバード流“NO”と言わせない交渉術 (知的生きかた文庫) 多分買う
本当は怖いC言語 多分買う
エンジニアの新しい働き方 この本じゃないかもしれないけど、派遣型技術者について何か1冊買う
パンツが見える。―羞恥心の現代史 (朝日選書) あのな(苦笑)
抜擢される人の人脈力 早回しで成長する人のセオリー 買うかな?
Joel on Software 多分買う
影響力の武器[第二版]―なぜ、人は動かされるのか 買うかな?
人を動かす 新装版 多分買う
予測力 「最初の2秒」で優位に立つ! 買うかな?
日本の「安心」はなぜ、消えたのか 社会心理学から見た現代日本の問題点 買うかな?
プロになるための データベース技術入門 MySQLforWindows困ったときに役立つ開発・運用ガイド 買わないかも
UNIXプログラミングの道具箱―プロフェッショナルが明かす研ぎ澄まされたツール群の使いこなし 買うかな?
ifとelseの思考術 プログラマ脳育成講座 買うかな?
プログラムはなぜ動くのか 第2版 知っておきたいプログラムの基礎知識 多分買う
コンピュータはなぜ動くのか~知っておきたいハードウエア&ソフトウエアの基礎知識~ 多分買う
痛快!コンピュータ学 (集英社文庫) 買うかな?
あなたはコンピュータを理解していますか? 10年後、20年後まで必ず役立つ根っこの部分がきっちりわかる! (サイエンス・アイ新書) 買うかな?
Web情報アーキテクチャ―最適なサイト構築のための論理的アプローチ 買うかな?
エキスパートCプログラミング―知られざるCの深層 (Ascii books) 買うかな?
欠陥ソフトウェアの経済学 ―その高すぎる代償― 買うかな?
悪いのは私じゃない症候群 持っていたが失くしてしまった。どうしよ?
フリー~〈無料〉からお金を生みだす新戦略 多分買う
ロングテール―「売れない商品」を宝の山に変える新戦略 多分買う
システム管理者の眠れない夜【新装改訂版】―本当に価値のあるシステムを求めて― 買うかな?
「暗黒のシステムインテグレーション」 -コンピュータ文化の夜明けのために (ITブッククラシックス) 買うかな?
成功する男はみな、「女子力」を使う 女性社員に好かれる24の法則 買わないかも
ハッカーと画家 コンピュータ時代の創造者たち 多分買う
アプレンティスシップ・パターン ―徒弟制度に学ぶ熟練技術者の技と心得 (Theory in practice) 絶対買う
オブジェクトデータベースのエッセンス 買うかな?
あたりまえだけどなかなかできない 37歳からのルール 買うかな?
一生、仕事で悩まないためのブッダの教え: シンプルに考える、自由に生きる (知的生きかた文庫) 買うかな?
禅、シンプル生活のすすめ (知的生きかた文庫) 買うかな?
対話で心をケアするスペシャリスト《精神対話士》の 人の話を「聴く」技術 多分買う
プロカウンセラーのコミュニケーション術 買わないかも
改訂新版 Cプログラミング診断室 多分買う
ねこ背は治る! ──知るだけで体が改善する「4つの意識」 買うかな?
バカの壁 買うかな?
ビジネス書を読んでもデキる人にはなれない 買うかな?
「超」入門 失敗の本質 日本軍と現代日本に共通する23の組織的ジレンマ 多分買う
2万ガメルを取り返せ!―ソード・ワールドRPGリプレイ集 バブリーズ編〈1〉 (富士見文庫―富士見ドラゴンブック) 多分買う
混沌魔術師の挑戦―ソード・ワールドRPGリプレイ集 バブリーズ編〈2〉 (富士見文庫―富士見ドラゴンブック) 多分買う
亡者の村に潜む闇―ソード・ワールドRPGリプレイ集 バブリーズ編〈3〉 (富士見ドラゴンブック) 多分買う
バブリーズ・フォーエバー―ソード・ワールドRPGリプレイ集バブリーズ編〈4〉 (富士見文庫―富士見ドラゴンブック) 多分買う
ブッタとシッタカブッタ〈1〉こたえはボクにある 買うかな?
ブッタとシッタカブッタ〈2〉そのまんまでいいよ 買うかな?
ブッタとシッタカブッタ〈3〉なぁんでもないよ 買うかな?
愛のシッタカブッタ―あけると気持ちがラクになる本 買うかな?
ブタのいどころ 買うかな?
ブタのふところ 買うかな?
ブとタのあいだ 買うかな?
ブタのみどころ 買うかな?
ココロが壊れないための「精神分析論」―加藤諦三教授の早大講義録 買わないかも
PHP公式資格教科書 PHP5技術者認定初級試験対応 (EXPERT EXPASS) 買うかな?
初めてのPHP5 買うかな?

テーマ:日記 - ジャンル:日記

  1. 2012/03/14(水) 21:42:49|
  2. 未購入書籍
  3. | トラックバック:0
  4. | コメント:0

値渡しと参照渡しの速度比較

今回の内容は、先月書いた値渡しで値を変えると処理速度が激遅になる時があるの続きなんですけど、
それについて、先日とある勉強会で話をして来ました。
で今回は、話をした内容をテキストにしたもの(自己紹介とかは除外してるけど)を書きたいと思います。
赤文字になっている箇所は、この記事の後半で補足しています。
また、横線の区切りはPPTのスライドのページ区切りと同一です。

-------------------------------------------------------------------------------------------------------
値渡しと参照渡しの比較
by kitoku
-------------------------------------------------------------------------------------------------------
[本題]
軽くブログ(前回の記事)の内容をおさらい
・値渡し後に引数の値を変えると、呼び出し元の値を維持する為に値のコピーが行われ時間がかかる
・よって、引数の値を変える場合には、参照渡しかオブジェクト指向のカプセル化(セッター)を使うと良い
-------------------------------------------------------------------------------------------------------
[引数のデータ型は関係あるか?]
・boolean、float、int、NULL、objectは、参照渡しの方が速いが気になるレベルの差でもないと思う*1
・resourceは差が出なかった。値の変更は、fopenで違うファイルを読むとしたのが原因か?
・stringと配列(数値か連想問わず)は、length(文字数や要素数)が多いほど、参照渡しの方が有利になる
-------------------------------------------------------------------------------------------------------
[文字列と配列が顕著なのは何故?]
・値を格納するメモリ領域のサイズが可変だからっぽい
・例えばintだと、値が0でもint_maxでも確保するメモリ領域のサイズは変わらないが、
文字列(文字の配列(PHPもC言語と同じっぽい))と配列(数値か連想問わず)だけは、文字数や要素数によって、サイズが変わる
・intなどでも時間差は発生するが、メモリ領域のサイズが変わらないので、微々たる差に留まる
←よって、文字列と配列の時に特に注意
-------------------------------------------------------------------------------------------------------
[処理の何処で時間がかかるのか?]
・引数の値を変える「瞬間」(コピーオンライトという仕組み)
・値渡しだと、関数の呼び出し元の値を保持する為、値のコピーが行われるが、コピーが行われるタイミングは、引数を渡した瞬間では「ない」
・だから値渡しでも、その引数の値を操作しなければ、時間はかからない
・コピーにかかる時間は、メモリ領域のサイズの大きさに比例する(だから文字列と配列が注意)
-------------------------------------------------------------------------------------------------------
[サンプルプログラムその1]
*2
function 関数名($引数A, $値A) {
  $引数A = $値A;←このタイミングで値のコピーが行われるので、この行の処理に時間がかかる
  return $引数A;
}

function 関数名($引数A, $値A) {
  $変数A = $引数A;←この場合は、値を変更していないので、値のコピーは行われず、時間もかからない
  return $変数A;
}

function 関数名($引数A, $値A) {
  $変数A = $引数A;
  $変数A = $値A;←これでも引数Aの値のコピーが行われる。変数Aと引数Aで同じメモリ領域を見てる?
  return $変数A;
}
-------------------------------------------------------------------------------------------------------
[サンプルプログラムその2]
*3
class クラス名 {
  public function メソッド名($引数A, $値A) {
    $引数A = $値A;←メソッドにしても所詮は値渡しされた引数の中身を変えているので結果は変わらない
    return $引数A;
  }
}

$変数A = 値B;
$変数B = new クラス名();
$変数A = 変数B->メソッド名($変数A, 値C);
-------------------------------------------------------------------------------------------------------
[サンプルプログラムその3]
class クラス名 {
  public function コンストラクタ() { $this->init(); }
  public function init() { $this->set_変数A(null); }
  public function set_変数A($変数B) { $this->変数A = $変数B; }
  public function get_変数A() { return $this->変数A; }
  public function メソッド名($値A) { $this->変数A = $値A; }
  private $変数A;
}

$変数C = new クラス名();
$変数C->set_変数A(値B);
$変数C->メソッド名(値C);
// 値を取得したければ「$変数C->get_変数A()」

値渡ししていても、その引数の中身を操作していないので問題ない
-------------------------------------------------------------------------------------------------------
で、終わりのはずが・・・
-------------------------------------------------------------------------------------------------------
[前回のブログ記事のはてブにこんなのが]
理屈では知っていても、結果を見ると改めて驚かされますね。ただ速度を考慮しないのであれば、参照渡しとか破壊系のメソッドとかは使いたくないしなぁ。
←破壊系のメソッドってなぁに?
-------------------------------------------------------------------------------------------------------
[破壊系のメソッド]
・オブジェクトの内部状態(値)を変えてしまうメソッド
・Rubyに多いみたい
・例えば、「$str = 'a';」の時、「$str->小文字を大文字に変えるメソッド();」を実行し、「戻り値がない」のに、$strが'A'になる様なメソッド
・つまり、自分で自分のクラスのメソッドを呼んでるのに、自分の内部状態を変えてしまうメソッド(ミュータブル的とも言う)
-------------------------------------------------------------------------------------------------------
[非破壊系のメソッド]
・オブジェクトの内部状態(値)を変えないメソッド
・さっきと逆で、内部状態を変えたい時には、戻り値が必要
・例えば、「$str = 'a';」の時、「$str = $str->小文字を大文字に変えるメソッド();」を実行すると、$strが'A'になる様なメソッド
・つまり、自分で自分のクラスのメソッドを呼ぶだけでは、自分の内部状態は変わらないメソッド(イミュータブル的とも言う)
-------------------------------------------------------------------------------------------------------
[で・・・]
・破壊的(ミュータブル的)と参照渡しとオブジェクト指向
・非破壊的(イミュータブル的)と値渡しと非オブジェクト指向
・これらって似てないか?
・前者はオブジェクトの状態が「変わる」が、後者は「変わらない」って角度で見たときに
-------------------------------------------------------------------------------------------------------
[イミュータブルなクラスのサンプル]
final class クラス名 {
  public function コンストラクタ($変数A) { $this->変数B = $変数Aをディープコピーする; }
  public function get_変数B() { return $変数Bをディープコピーする; }
  public function メソッド名($値A) { new 自分のクラス名($値A); }
  private final(PHPは変数にfinal書けないけど) $変数B;
}

$変数C = new クラス名(値B);
$変数C->メソッド名(値C);
// 値を取得したければ「$変数C->get_変数A()」

値渡しした引数の中身を変えていない(というかfinalだと変えれない)ので、速度は低下しない
-------------------------------------------------------------------------------------------------------
[ミュータブルとイミュータブルの比較]
・イミュータブル

メリット:
1.変数の値(オブジェクトの状態)の変化に気を使う必要がないので使いやすい

デメリット:
1.(値渡しは)複数の戻り値を返しにくい*4
2.(値渡しは)値のコピーに処理時間がかかる
3.(イミュータブルは)不変なので、値を変えたい時には新たにインスタンスを生成しなければならない(コスト的にどうか)
4.(イミュータブルは)finalなので継承が出来ない。よって拡張性に欠ける
-------------------------------------------------------------------------------------------------------
[ミュータブルとイミュータブルの比較]
・ミュータブル

メリット:
1.(参照渡しは)複数の戻り値を返しやすい*5
2.引数は「(多分)メモリのアドレスを参照しているだけなので実態をコピーする必要がなく」処理時間がかからない
3.値を変えたい時に、インスタンスを生成する必要がない
4.finalじゃないので、継承したりして拡張出来る

デメリット:
1.引数の値(オブジェクトの状態)の変化に気を使う必要があるので使いにくい

とはいえデメリットについて。
値を変えたい変数は引数で渡さずに、必ずセッター経由で値を変える様にすると、
セッター内でデバッグすれば(どのファイルのどの行から呼ばれたかを調べる)きっちり監視できる
-------------------------------------------------------------------------------------------------------
[ミュータブルの方が良い別の理由]
ソフトウェアは、機能追加や改修により「成長」していくもの(アジャイルが典型的)
保守性の高さがウリと思う、オブジェクト指向(つまりミュータブル)は、そういった意味でソフトウェア開発に合っていると考える
だから、ミュータブルの方が良いと思う
といっても、イミュータブルの方が良い時がある可能性も否定はしない(どういう時かは不明)
-------------------------------------------------------------------------------------------------------
[結論]
ミュータブルの方が扱いが難しいかもしれないが、頑張って勉強して使いこなそう!
イミュータブルも、使える局面があった時に使える様に勉強はしておこう!
今回の話が、皆さんのより良いソフトウェア開発ライフの一助になれば幸いです
-------------------------------------------------------------------------------------------------------

ここからは、上記本文中の「*」についての補足です。

*1→秒数の差は、値渡しか参照渡しをする以外は処理に差異がない関数を1000000回呼び出して0.1秒前後でした
*2→値渡しをしている前提です
*3→*2と同じ
*4→関数内で変更した変数を、1つずつ配列に追加していけば出来るが、要素の何番目にどの変数が入っているかを意識しないといけないので、微妙だと思います
*5→複数の戻り値ではなく、関数内で複数の変数の値を変更して呼び出し元に反映できるという意味です

また、話した時に頂いた質問についても、以下で触れてみます。
ちなみに、他にも質問がありましたが忘れました(苦笑)
終わった後にすぐまとめたほうが良いですねぇ。

Q.ミュータブルにすると何がオイシイのか?

A.アジャイルとの相性が良い辺り。また、イミュータブルだと本文の通りオイシクない時があるので、相対的にミュータブルがオイシくなると思います

Q.objectはクラス構成(メンバーの数などクラスの大きさ)によって速度が変わるのでは?

A.構成を変えて試してはいないので分からない。あくまでも今回は、同じ構成で値渡しと参照渡しをした時の速度比較した時の話です

最後に、ウチ自身の継続課題などを。

ミュータブルだと、マルチスレッドの時に値の書き換えを心配しないといけないのでは

Webだと、リクエスト(スレッド)ごとにインスタンスを生成すれば、
値を共有することはない?

シングルトンは?

シングルトンは、単一のインスタンスをずっと変えない性質なのでイミュータブルと少し似ている?
であれば、少なくとも積極的に使う必要はないと思う。
疑似グローバルという側面もあるので。

PHPの内部的には一体どうなっているのか?

PHPのデータ構造を読む。
といってもこの辺は、C言語の知識の応用で事足りる?

とりあえず今回はこんな所です。

<追記>
えっと、PHPの関数では、参照渡しよりもreturnしたほうが速い!?というページを見つけました。
で、ウチも検証してみましたが、確かに2倍ぐらい差が出ます。
ただ、今回の記事と違って、値渡しを「していない(正確にはする必要がない)」ので、
そもそも引数が不要な場合(引数の値を関数内で使う必要がない場合)には、
参照渡しよりreturnで戻り値を返した方が良いよって事だと思います。
また、多分突っ込みで、
「この関数が終わった後に、他のクラスで使いたいから参照じゃないとダメなんだ」っていうのがあるかもしれませんが、
それなら、関数が終わった後にセッターに代入しておけば良いのではと思います。
といってもまあ、これはワリと本気で、
クラス構成(こっちは上手く組めば無い?)や処理の流れ(特にコッチ)によっては、
参照渡しにせざるを得ないケースもあるかもしれません。
まぁ、なかなか難しい所だと思います。
以上です。

テーマ:日記 - ジャンル:日記

  1. 2012/02/19(日) 21:25:48|
  2. PHP
  3. | トラックバック:0
  4. | コメント:0

主導権は常に自分にあるけど、迷った時には

かなり前に発売された作品ですが、
先日椎名林檎さんの「短篇キネマ 百色眼鏡」を観て、タイトルの事を思いました。
まぁ、当然っちゃあ当然なんでしょうけど、意外と意識から抜けるのではと思いまして。

先に結論です。
「自分を信じ切れないのなら、自己分析したり他人に相談するしかないのでは」ですかね。
特に、自己分析が重要かと。
で、もし自己分析が出来ないなら、他人に分析してもらうと。
では、作品の内容も踏まえつつ、以下から詳しく書いてみます。
あと、内容を知らなくても理解しやすい様に書いたつもりです。

まず、作品内でヒロインの葛城楓は「多面性」を顕著に見せていますが、
それって別に誰でもそうだと思うんですよね。
プライベートの顔と仕事の顔とか。
意識的かそうでないかはともかく、
対峙する相手との関係性によって、色々な顔が出ると思います。
で、そうすると、どっちが本当なのかって気持ちになるかもしれないですが、
どっち「も」本当だと思うんです。
じゃあ、嘘は無いのかって話になるかもしれませんが、
とある人に嘘を付いた自分も、それも本当の自分なのではないかと。
話した内容自体は嘘でも、「自分が嘘を付いたという言動」は本当ですよね。
まぁ、別に嘘を付いて良いとは思いませんけど。
でも、一人の人間なのに、色々な顔を見せられたら。
主人公の天城の様な優柔不断(だと感じました。それが必ずしも悪いとは思わないですけど)な人は、
どっちが本当なのかとか、
自分はどっちの楓を選べば良いのかと、思うのは無理もないと思います。
でもそれって、「自分が決めてよいこと」だと思うんです。
他人の「全て」を理解することなど、
他人を知ろうとした所でまず不可能ですし。
他人を知る努力はした方が良いにしても、
自分が見た他人が全てなわけであり、
見ていくうちに印象が変わったのなら、それなら印象も変えれば良い。

身も蓋もない話をすれば。
上記でも書いた通り、
相手や物事をどう位置付けるかの、主導権は自分にあると。
そして、自分がどんな選択をしても、因果応報よろしくその選択に見合った結果が出ると思います。
真っ当な自浄作用が利く組織や業界なら、真っ当な結果が出るでしょうし。
だから、自分を信じて相手なり物事なりを位置付けていけば良いんじゃないかと。
自分が信じたいものとは違うものならスルーしたり、
自分にとって痛いものなら触れないようにしたり、
自分が理解出来ないものなら理解しないで、
生きていけば良いんじゃないかと。
と言いつつも、ウチにはそれは出来ないですけど。
でも、もし自分にそこまでの自信が無くて決断出来ないのなら。
どうして決断出来ないかを自己分析するなり、
他人に相談して助言を頂くなりしなければ。
永久に決断出来なくて、いつまでも迷い続けるんじゃないかと思うんですけどねぇ。
あと、「相手を想って適切な助言が出来る」人って、
個人的な印象では少ないと思うので、その辺にも要注意でしょうかね。
また、自信を持てない原因が他人の言動にあるなら。
どうしてあの人はあんな言動をするのかとかを、考えることが大事なんじゃないかと。

自分の人生を他人が代わりに生きることは出来ないです。
この記事を読んでもそうだと思いますが、
まさに、「どうするかは自分次第」なんでしょう。
個人的には、百色眼鏡は良い作品でしたね。

参考:
スルー力、ねぇ
百色眼鏡の意味を考えるスレ

テーマ:日記 - ジャンル:日記

  1. 2012/02/13(月) 00:02:59|
  2. 思想
  3. | トラックバック:0
  4. | コメント:0
次のページ