愛から憎しみへ-一歩、またはActiveRecordで魔法を愛するのをやめた方法

最近、プロジェクトの1つで興味深い問題が発生しました。非常に長い間、REST APIのデータはわずかながらも提供されていました。 何が起こったのか、そしてその理由-私はあなたに話をする。



データベースからの情報が管理パネルに表示され、ページあたり20エントリ+リンクが強化されました。 50(!!!)秒かかりました。 基地で何が起こっているかを見ないのは罪だった。 5万件のレコード、フィルタリングのための約6〜7の結合、および6〜7の積極的な読み込み要求では、このようなブレーキが発生する可能性があるとは思いませんでした。



そのため、すべてのリクエストで約0.18秒かかりましたが、これはまったく問題ありません。



さて、さらに掘り下げます。 そして、モデルのシリアル化にすべての時間が費やされていることに気付いたとき、私のinりは際限がありませんでした。 これはどうですか?



class OrderController { public function index(Request $request, OrderFilter $filter) { //   $query = $filter->applyFilters($request); //   return $query->paginate($request->input('count', 20)); } }
      
      





ディスパッチャーは、クライアントの要求に応じてコントローラーの結果の変換を開始します。 もちろん、彼はAccept: application/json



というタイトルを見て、汚い仕事を始めました。 そして、熱が始まりました。



各モデル、各接続、そして多くのメソッドが再帰的に呼び出されます-マジックゲッター、ミューテーター、カースト。



同じ邪悪なコード
 /** * Convert the model's attributes to an array. * * @return array */ public function attributesToArray() { $attributes = $this->getArrayableAttributes(); // If an attribute is a date, we will cast it to a string after converting it // to a DateTime / Carbon instance. This is so we will get some consistent // formatting while accessing attributes vs. arraying / JSONing a model. foreach ($this->getDates() as $key) { if (! isset($attributes[$key])) { continue; } $attributes[$key] = $this->serializeDate( $this->asDateTime($attributes[$key]) ); } $mutatedAttributes = $this->getMutatedAttributes(); // We want to spin through all the mutated attributes for this model and call // the mutator for the attribute. We cache off every mutated attributes so // we don't have to constantly check on attributes that actually change. foreach ($mutatedAttributes as $key) { if (! array_key_exists($key, $attributes)) { continue; } $attributes[$key] = $this->mutateAttributeForArray( $key, $attributes[$key] ); } // Next we will handle any casts that have been setup for this model and cast // the values to their appropriate type. If the attribute has a mutator we // will not perform the cast on those attributes to avoid any confusion. foreach ($this->getCasts() as $key => $value) { if (! array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) { continue; } $attributes[$key] = $this->castAttribute( $key, $attributes[$key] ); if ($attributes[$key] && ($value === 'date' || $value === 'datetime')) { $attributes[$key] = $this->serializeDate($attributes[$key]); } } // Here we will grab all of the appended, calculated attributes to this model // as these attributes are not really in the attributes array, but are run // when we need to array or JSON the model for convenience to the coder. foreach ($this->getArrayableAppends() as $key) { $attributes[$key] = $this->mutateAttributeForArray($key, null); } return $attributes; }
      
      







もちろん、ミューテーターは非常に便利です。 モデル/関係のさまざまなデータにアクセスできるのはクールで美しいことですが、ドキュメントページでは、開発者が書くのが面倒で、その使用がパフォーマンスに大きな影響(大きな影響を与えたい)であると書いています。



そしてここで、列車がすでに非常に高速化されており、datamapper / querybuilderですべてをやり直す時間がないという理解があります。 ActiveRecordのトラフにとどまりました。 私はこの魔法が好きですが、あなたはそれを悪用することはできません。



何も壊さないようにするために、私はRedisに連絡する必要がありました。Redisにはすべてのデータが含まれており、モデルの更新後に定期的に更新されます。 しかし、そこにありました! データ量が非常に大きいため、Redisが落ちました(私には罪があります。おそらくそれを引き締める必要がありました)。 標準の64MBは良くないので、gzcompressを介してデータを渡す必要がありました。 また、別のインスタンスが開始されたため、Redisに負荷がかからないという確信がありました。



これですべてが機能し、すべてが正常になりました。 データは0.5秒未満で与えられ、誰もが幸せです。 しかし、私は座り、「スピードとシンプルさを備えたBribes Laravelを考えますが、次のプロジェクトは間違いなくこれらのActiveRecordなしです。」



それが物語の終わりであり、よく聞いた人なら誰でもボトネコフは逃げます。



All Articles