web-dev-qa-db-ja.com

オンザフライでデータベーステーブルを変更する、なぜこれが悪いアイデアなのですか?

私は最近StackOverflowに関するコメントを見ました。基本的に、その場でテーブルを変更することは悪い考えだと述べています。

私の場合、「製品」に関する情報を格納するjsonファイルがあります。これらの情報の1つは、データテーブルのどの列がこの製品に関連しているかを他のプログラムに伝えます。このidはユーザー定義ではありません。

phpファイルから製品を追加/削除できるjson関数がいくつかありますが、これらの関数の実行中は、テーブルの列を追加または削除する必要があります。

$sql = 'ALTER TABLE products ADD p'.$id.' VARCHAR(11)';
$stmt = $mysql->prepare($sql);
$execute = $stmt->execute();
if($execute!==false){
    $build = ["name"=>$product_name, "release"=>$release_date, "details"=>$details, "id"=>$id];
    array_Push($products["products"],$build);
    $products = json_encode($products,JSON_PRETTY_PRINT);
    $file = fopen("./crm.json","w+");
    fwrite($file,$products);
    fclose($file);  
}else{
    //error message
}   

これが悪い考えである理由を誰かが説明できますか?

詳細:

私の特定のケースについてもう少し説明すると、jsonファイルには私の製品情報のallが格納されます。各製品エントリのidは、ユーザーがこの製品を使用しているかどうかを確認するために、テーブルでどの列を参照する必要があるかを示すために使用されます。それ以外に、idは、製品が削除された場合に削除する必要がある列を知るために使用されます。以下はjsonサンプルです

{
    "location": "Test Location",
    "products": [
        {
            "name": "SAMPLE PRODUCT",
            "release": "2019-12-04",
            "details": "RANDOM PRODUCT DETAILS",
            "id": 1
        },
        {
            "name": "SAMPLE PRODUCT",
            "release": "2019-12-04",
            "details": "RANDOM PRODUCT DETAILS",
            "id": 2
        },
        {
            "name": "SAMPLE PRODUCT",
            "release": "2019-12-04",
            "details": "RANDOM PRODUCT DETAILS",
            "id": 3
        }
    ]
}
3
FamousAv8er

場合によります。異なるプロセスまたはプログラム間でデータを共有するためにデータベーステーブルが使用され、スキーマの構造を変更している間に別のスキーマがアクセスすると、衝突が発生するので、これは特に悪い考えです。

ただし、特定の制限された状況下では、これが可能な解決策になる可能性があります。だが

あなたはあなたが何をしているのか正確に知る必要があります!!!

  • テーブルは、少なくとも変更が発生したときに、テーブルを変更するプロセスによって排他的に使用される必要があります。他のプロセスが変更時にそれを使用しようとする必要はありません。

  • 変更されたテーブルを使用するプロセスは、作成プロセスと同じ動的な方法でそれを使用する必要があります。これはおそらく、変更されたテーブルにどの列があるかを調べる必要があります。 特定のテーブルの列名を取得するベンダーに依存しない標準的な方法はありませんであることに注意してください。通常、実行時に列を特定するために、DBMS固有のシステムテーブルにクエリを実行する必要があります。これは通常、ORMのようなものと一緒に機能しません。ORMは、多くの場合、固定されたdbスキーマに依存しています。

  • プロセスには、テーブルを変更するための十分なアクセス権が必要です。小さなシステムの場合、これは許容できる場合があります。大きなシステムの場合、バグが発生した場合にデータの損失を防ぐために、これらのアクセス権を与えないことをお勧めします。

  • テーブルに列を追加するときはいつでも、関連するインデックスや、おそらく外部キー制約を追加または再構築する必要があります。これは、実行時のパフォーマンスに重大な影響を与える可能性があります。

そのようなアプローチが実行可能な典型的な使用例は、ETLプロセスである可能性があります。これは、JSONファイルのコンテンツを、それがロードされる前に、独自の排他的な使用のために中間の一時テーブルにインポートします。スキーマが固定された「通常の」データベース。

そこで、それがここでの種類のケースであるかどうか、動的に生成された列を使用することで本当にメリットがあるかどうか、またはJSONインポート用に固定されたままの方法でスキーマを異なる方法でモデル化できないかどうかを確認してください。

あなたの質問の例にメモを追加しましょう:あなたが説明したものの標準モデリングは次のようになります:

  • 1つのProductテーブルと主キーproductId

  • 1つのCustomerテーブルと主キーcustomerId

  • 外部キーUsedByおよびproductId(および適切なインデックス)の列を持つ1つのリンクテーブルcustomerId。顧客が特定の製品を使用するすべての組み合わせに対して1つのレコードが含まれます。

これは、実行時に列を追加または削除する必要はありません。これは、顧客や製品などのエンティティ間のn:m関係をモデリングする標準的な方法です。リレーショナルデータベースは、列を動的に追加するのではなく、そのように関係を処理するために設計されています。

4
Doc Brown

データベースは固定され、バージョン管理されたスキーマを持つ必要があるため、これは悪い考えです。
このようにして、データベースの特定の移行で追跡できます。

Jsonが受信データの主要なスキームを表す場合は、それに応じてデータベースの移行を提供する必要があります。


また、製品に関する追加情報を列名に格納しているようです。これはかなり正規化され、productsテーブルの外部キー列によって参照されている使用可能な製品IDを保持する追加のテーブルに保存されます。

4

私はあなたが何をしているのかわかります。 なぜについてより深く理解していないと、このデザインを選択したことになります。それが「良いアイデア」であるかどうかは言えません。

そうは言っても、あなたはあなたがこのことについて単に学んでいると述べました。そして、そのような設計のために合成できる唯一のユースケースは、システムが単一のクエリに対して最適化する必要がある場合、「この製品を使用する顧客の数は?」です。私はデータベースの専門家ではないので(誰かが私を訂正してくれるかもしれません)、従来の結合テーブルを使用してcustomer_idおよびproduct_id(顧客、製品)の組み合わせごとにインデックスを作成できるため。データ型に関するいくつかの詳細に応じて、スペース効率も向上すると思います。

上記を念頭に置いて、私は控えめに言っても疑わしいです!代替のより正規化されたアプローチよりも設計を使用して、特定の一般的な種類のクエリ(たとえば、「各顧客の平均製品価格は?」)を発行するとき、かなりの速度と利便性をトレードオフしています。

2つのテーブル(「customer」と「product」)を使用する代わりに、3つのテーブル(「customer」、「product」、「product_usage」)を使用して、顧客情報、製品情報、および「どの顧客がどの製品」それぞれ。 「product_usage」には2つの列が必要です:customer_idおよびproduct_id(代理キーを維持したい場合は、おそらく3分の1)。

上記の設計は柔軟性を最適化します。これが好ましいかもしれません。

1
king-side-slide