web-dev-qa-db-ja.com

リレーショナルデータベースを非リレーショナルDBを含むソフトウェア製品の「貧弱な」設計に置き換えますか?

Edit:この質問は、システムの一部が共通の標準から逸脱したシステム全体の設計。たとえば、ビジネスモデルのすべてを、リレーショナル整合性に至るまで、独自のプログラムコードで管理します。これにより、構造化ストレージではなく、データベースと永続化レイヤーに「何かをダンプして、なんとかして再び出力する」場所として使用することで、設計の悪臭を放ちます。私が質問したのは、NoSQLドキュメントストレージは、既にスキーマのない(または非常にルーズなスキーマ)データベースをデフォルトでスキーマのないデータベースに移動するオプションのように思えるからです。また、ここで説明されているいくつかの欠陥にもかかわらず、システム全体がまったく悪いものではないことにも注意する必要があります。また、バージョン管理などの一部の問題には、解決策があるか、すでに実装されています。

クラシックなリレーショナルデータベース(SQL Server、Oracle)、NHibernateをオブジェクトリレーショナルマッパー(ORM)、ビジネスロジックモデルレイヤー、および膨大な数のモジュール(数100)として見たソフトウェアシステムを考えてみてください、主に.NETベースのサービスといくつかのWebサービス(クライアント、システム/顧客ごとに最大100以下、企業ネットワーク、非公開)。操作スタイルは主にOLTPで、書き込み/ CUDアクセスはワークロードのインポートおよび一部です。生産的なデータベースは通常約10 GBですが、常にサイズが100 GBをはるかに下回ります(したがって、「ビッグデータ」はありません)。それはうまくいきますが、私にとって、データベースとORM実装は、いくつかのアンチパターン(リレーショナルデータベースの場合)の匂いがします。おそらく、これらの実装は、別の種類のデータベース(ドキュメント指向(「NoSQL」)またはインメモリデータベース)の方が優れている場合があります。

  1. 多くのリレーショナルデータベースとサポートするORM機能が省略されています:テーブルは非常に非正規化されており、外部キーリレーションが欠落しているか不可能です。メタデータテーブルが_IdInTable INT, OwnerTable INT_のような列を持つ異なるメインテーブルを参照するため。 NHibernateには、ほとんどの場合、オブジェクトの関係がマッピングされていません(また、一般に、作成されていないテーブル構造に問題があります)。代わりに、これらはビジネスロジックに実装されます(孤立した子オブジェクトまたは非効率的なデータベースアクセスにつながることがあります。以下を参照してください)。

  2. 基本を下回る非正規化:1番目以外のNFデータの使用の増加:XMLを持つnclob/nvarchar(max)列、コンマ区切りリスト、または複合数値列(たとえば、タスクタイプ123の123、10123、40123、ただしモジュール構成が異なる) 0,1,4 * 10000で識別されます)。最初の2つには、データベース関連の論理的な「外部キー」と、_<UserType>AdminUser</UserType>_(_LIKE '%...%'_でチェックされる)などのデータモデル関連の値が含まれます。これは主に、メインスキーマに入れるべきではない、またはXML値を使用して実装するのが簡単な、リリースまでの時間が短く、カスタマイズされた値が多いためです。

  3. トリガー、フォローアップストアドプロシージャ、またはアプリケーションによって他のテーブルにコピーされるテーブルの内容を含む、2番目以外のNFデータ。たとえば、一部のアプリケーションはメタデータまたは水平メタデータしか使用できないため、「垂直」メタデータテーブルにコピーされたテーブル列値、これもメタデータの「水平」または「ピボット」表現にコピーされます(各メタデータタイプは列)。 。 「ごみ箱の構造」を使用する頻繁な要求(さまざまなソースから収集したデータを1つのnclob/nvarchar(max)の「ごみ箱」列にダンプし、アプリケーションが多くの異なるソースの代わりにそれを検索できるようにします)。

  4. ビジネスロジックモデルとアプリケーションの「1つのオブジェクトの病気」:単一オブジェクトの反復と即時のロード/保存:ビジネスレイヤーは、個々のオブジェクトのLoad/Save()メソッドを主に使用し、バルク/セットベースの操作をほとんど使用しません。一般的な仕事は、SQLまたはそのNHibernate表現によってオブジェクトIDを取得し、取得したすべてのIDを反復処理し、foreach (oneId in Ids) { myObjects.Add( BizModel.GetMyObjectById(oneId) ); }のスタイルでオブジェクトを1つずつフェッチすることです。これには、すべてのメタデータ、依存オブジェクトコレクションなどがあり、従来のSELECT N + 1の状況です。さらに、NHibernateのキャッシング、永続性の無視、および複合操作のほとんどは無効になっています。1つのオブジェクトをロードすると、明示的に_SELECT FROM MyObject WHERE Id=:id_が呼び出され、キャッシュの使用や遅延実行が防止されますが、現在のDB行から新しいオブジェクトが取得されます。 MyObject.Save()は、即時の挿入/更新を強制するために実装されています:NHibernate session.Save(...)の直後に.Flush()が続きます。全体はNHibernateマイクロセッションを使用します。読み込まれたオブジェクトはすぐにセッションコンテキストから取り出され、新しいセッション内に保存されます(DBで保存されていないオブジェクトの「奇妙な」不要な変更を防止します)。 NHibernateによる永続性の無知とオブジェクトの関係は、すべてのオブジェクトの状態を制御し続けるには望ましくないようです。 NHibernateは、リレーショナルデータベースアクセスのための複雑なツールではなく、実際にはマッパー(1行から1つのオブジェクト)と見なされています。 NHibernateの代わりに「高速な」micro-ORMを使用することについての議論もあります。これはSELECT N + 1クエリをオブジェクトに高速で実現しますが、N + 1自体に対しては何もしません。

  5. 変更ごとにすべてのモジュールをリリースするのは多すぎるので、すべてをすべてで機能させることが重要な要件です。新しいモジュールは、特定の列とテーブルが存在しない古いデータベースバージョンと古いモジュールで動作する必要があります。列などが追加された新しいDBバージョンでも動作する必要があります。これにより、削除によって古いモジュールがクラッシュする可能性があるため、nullにできない場合はデフォルト値を持つ新しい列があり、長い間放棄された古いテーブル/列がまだデータモデルに残っています。もう1つの結果は、新しいテーブル/列を追加することをためらうことです。これは、リリースされると、ほとんど取り除くことができません。代わりに、XML(テキスト列)と同様の非正規化されたもの、またはグローバルメタデータテーブルのプロパティ値が推奨されます。

  6. 多くのモジュールは、単一のオブジェクトだけのタスクを受け取ります。これは、セット/バルクデータアクセスメソッドが必要に応じて単一のオブジェクト/行も処理できるため、可能なセットベースのアプローチでは問題ありません。一方、多くのオブジェクトを一度に処理し、ビジネスロジックを必要とし、現在の単一オブジェクトの方法(ネイティブSQLを使用するWebサービス、または新しく、 Luceneベースの検索エンジン。目的のオブジェクトのIDを検索しますが、モデルオブジェクト全体を1つずつ取得します)。

想像してみてください、あなたはこれを変えようとしました。初めは、NHibernateとその機能については知りませんでしたが、データアクセスを実際の機能に適合させ、不必要なデータベース操作を回避する方法を考え出しました。NHibernateで関係をマップし、セッションとトランザクションをいくつか開いたままにしますオブジェクト操作、セット/バルク操作、数年前に学んだ方法でのDBの正規化、外部キー、ビュー、場合によってはマテリアライズドビューの追加。しかし、あなたは次のような引数で拒否され続けます: "誰もそれを支払うつもりはありません" "データベースアプリケーションがどんなに「悪い」ものであってもそれを処理できます "、そして単に"それは機能します "。ディスク容量、メモリ、CPUパワー、ネットワークリソースは安価です。データアクセスのリファクタリングははるかにコストがかかります。おそらく、DBプログラマーのセットベースのアプローチではなく、コードプログラマーのオブジェクト指向のアプローチを採用する方が望ましい(ORM実装に対する実施を含む)。現在の方法で十分に機能している場合、システムが10倍または100倍高速になる可能性がある場合、何が問題になりますか?とにかくSELECT N + 1を気にしないでください。今日のデータベースはそれを処理できます!それは金メッキだけでしょう!データベースがテラバイトに成長すると、状況が変わる可能性がありますが、現時点ではそうではありません。

したがって、おそらく、「NoSQL」または「NewSQL」領域に解決策があります。高速かつ効率的な方法で、オブジェクトをデータベースからフェッチしてデータベースに格納できる場合があります。長い距離のレイテンシのないローカルDBである限り、セットアプローチではなく、単一のオブジェクトに多くのクエリがあっても。現在のシステムはリレーショナルデータベースを拡張された永続的なメインメモリとして使用しているようであり、テーブルとインデックスを手動で作成および維持したり、オブジェクトをリレーショナルテーブルにマッピングしたりするなど、ITの「石器時代の遺物」すべてを巨大なオーバーヘッド。

私の考えは:

「NoSQL」ドキュメントデータベースは、次の理由で優れています。

  • ドキュメントには主に、依存するアイテム、メタデータ、およびそれに属するすべてのオブジェクトグラフ全体が含まれているため、追加のDBクエリを必要としないため、SELECT N + 1の問題を回避または大幅に削減できます。
  • ドキュメント内では、依存オブジェクトが親に​​含まれている(XMLまたはJSON表現でネストされている)ことにより、暗黙的な「リレーショナル整合性」が存在します。
  • 複数の異なるドキュメントにわたって、データベースには関係はありません。これらはビジネスロジックによってのみ維持されます(現在は頻繁に行われていますが、従来のリレーショナルDB設計では間違っています)。
  • 通常は固定スキーマがないため、データ構造の変更を処理する方がはるかに簡単です。オブジェクトは、後で追加されたプロパティを無視するか、古いバージョンのデータから欠落している値をデフォルトで埋めることができます。
  • 外部/変数/スキーマのない後続のデータは、(リレーショナルテキスト列にXMLを格納するのではなく)中断することなく統合できます。
  • 多くのドキュメントDBには、自動インデックス作成または検索エンジンが統合されています。

最低限の自動化されたデータ整合性、特にマルチオブジェクトトランザクションは依然として必要です。

インメモリリレーショナルデータベース、またはすべての(書き込み)操作で低速のハードドライブにアクセスする必要のない高速アクセスに焦点を当てたものは、速度を向上させますが、基本的にはハードリレーショナルスキーマに依存しています。利害関係者にとって望ましくないようです。

経験のある人が私の仮定が正しいかどうか教えてもらえますか?

5
Erik Hart

データベース地獄へようこそ!

NoSQLは、これらのタイプのアプリケーションのソリューションとしてしばしば支持されています。ただし、ここでの問題は、プログラマーが何をしているのかまったくわからないことです。さらに、あなたの経営陣は変更を恐れているか、正確にリストして根本的な原因を修正する可能性が高い難しい決定を下したくないようです。データベースを別のデータベースに置き換えることがここで役立つことは非常に不確実です。ツールのせいではなく、職人のせいです。

NoSQLのすべてのオブジェクトにオブジェクトグラフ全体を含めることができるのは事実ですが、適切な整合性を維持してすべてのデータを最新の状態に保つ方法がまだあります。ちなみに、これは3NFが解決するために作られたものであり、適切に設計されたすべてのシステムで美しく解決されます。冗長データを維持すると(SQLとNoSQLのどちらでも)、同期と同期を保つためのロックとラッチに関するあらゆる種類の問題が発生します。

NoSQLの動的スキーマの性質は、スキーマが非常に頻繁に変更される場合にのみ利点があります。あなたのシステムの説明から、誰もコードに触れようとしないので、これはそうではないように聞こえます。さらに、リレーショナルデータベースでのスキーマの変更はそれほど難しくありません。 NoSQLが推進する動的スキーマの利点は、主に、自分が何をしているのかを知っているDBAには存在しない問題を探すソリューションです。

NoSQLの理論的なメリットを享受できたとしても、現在直面しているすべての同じ議論に遭遇することなく、現在の場所から移行する方法について考える必要があります。 2つのアプローチを比較するコストは、根本的な変化に開かれていない環境では法外なものになるでしょう。

ここで解決策を模索している理由を完全に理解しています。しかし、ITには多くの素晴らしい仕事があります。このタイプのシステムと組織に対処するには、人生は短すぎます。忍耐力と苦痛の忍耐力のレッスンが必要でない限り、先に進んでください。

5
Thomas Kejser

実行中のシステムに触れないでください。特に、付加価値を付けずに「より良い」システムにするためではありません。いくつかの機能を追加し、同じクラスで何らかのリファクタリングを実行できる場合は、それを実行し、徹底的にテストします。しかし、それを変更するためだけでは決してありません。

ほとんどの場合、NoSQLはドキュメント全体を読み取り、保存します。これは、説明した休止状態のマッピングと同じであるため、パフォーマンスが向上することさえありません。それはすべてのデータをメモリに保持するので、たとえばインデックスがある場合、10 GBはメモリ内ではるかに多くなります。

SQLでは、複数のテーブルのTable + IDを、nullの可能性があるテーブルごとに1つの外部キーに分割できます。

NoSQLは素晴らしいですが、制限(および実際のデータ)を使用して制限を確認する必要があります。このユースケースでは、どちらが優れているかはわかりません。また、SQLはすでに存在しているため、前述のように一括操作を使用してパフォーマンスを向上させることをお勧めします。そこでは、改善の大きさを実際に測定する必要があります。 30ミリ秒ではなく15ミリ秒待つことは、ほとんどのユーザーにとっておそらく面白くないでしょう。

0
user47850

@Erik 150 mphの車を、その楽しみのためだけに200 mphを実行できる車に置き換えるのではありません。パフォーマンスの問題に遭遇する顧客がいる場合、または新しい顧客を獲得した場合、より多くの電力が必要になります。しかし、正気な人がソフトウェア全体を書き直して同じことをやり直すために莫大なお金を費やすことはありません。そして、あなたが自分自身が狭い心であるときにちょうど人々バカを呼ぶことはあなたをより賢くするか、またはより正しくしません。

実際のプロジェクト/顧客を意味する変更の必要性があり、次にオプションを調べて、dbレイアウトをよりスマートにするか、クエリプログラムを作成するか、dbを置き換えます。しかし、物事を変えることを期待することはできません。

私が覚えている限りでは、Hibernateは子要素の遅延読み込みを行ったので、操作のためにメインオブジェクトを読み込むだけで済みます。それは本当に重要ではありません、それは変化の必要があるまでそれが何であるかを維持します。 IPを成長させ、それを受け入れることを学ぶか、「より良い」ことを行う自社を見つけますが、他の企業の2倍の開発コストで事業を使い果たした理由を従業員に説明します。

ここでは新しいプロジェクトについて話しているのではありません。変更する必要のない既存の実行中のレガシーシステムです。言及した20mphなどの問題が発生する場合を除きます。そうですか?たった今?それともあなたは将来それを期待していますか?

修理しますか?番号、

これがあなたが失敗する理由です。答えは、適切なタイミングであれば、「はい」ではなく「はい」です。

0
Epi