3

SQL テーブルの簡単な例を次に示します。

CREATE TABLE persons
(
    id INTEGER,
    name VARCHAR(255),
    height DOUBLE
);  

私は SQL をあまり使用したことがないので、SQL の用語で考える方法をまだ学んでいません。事実上、私の脳は上記を次のように翻訳します。

struct Person
{
    int id;
    string name;
    double height;

    Person(int id_, const char* name_, double height_)
    :id(id_),name(name_),height(height_)
    {}
};
Person persons[64];

次に、いくつかの要素を SQL に挿入します。

INSERT INTO persons (id, name, height) VALUES (1234, 'Frank', 5.125);
INSERT INTO persons (id, name, height) VALUES (5678, 'Jesse', 6.333);

...そして私はそれをどのように考えていますか:

persons[0] = Person(1234, "Frank", 5.125);
persons[1] = Person(5678, "Jesse", 6.333);

SQL は、データ操作とデータ定義という 2 つの主要部分と見なすことができると読んだことがあります。データのクエリや変更よりも、データの整理に関心があります。そこでは、SQL の違いがすぐにわかります。私には、SQL でデータを構造化する方法と構造化する方法の微妙な点は、よりあいまいなトピックのように思えます。私が自分自身のために自動的に描いている構造体の配列のアナロジーはどこで壊れますか?

具体的な例を挙げると、personsテーブル (または各Personオブジェクト) の各エントリに、その人の子供 (階層データ構造の子供ではなく、実際の子供) の名前を示すフィールドを含めるとします。 )。実際には、これらはテーブル間の参照 (またはオブジェクトへのポインター) である可能性がありますが、単純にして、このフィールドに 0 個以上の名前が含まれるようにしましょう。私の C++ の例では、次のように宣言を変更します。

vector<string> namesOfChildren;

...そして、次のようにします:

persons[0].namesOfChildren.push_back("John");
persons[0].namesOfChildren.push_back("Jane");

しかし、私が知る限り、SQL の一般的な使用法はこのアプローチを反映していません。私が間違っていて、シンプルで簡単な解決策があれば、素晴らしいです。そうでない場合は、私のような SQL の初心者は、SQL テーブルのデータベースが、生の一般的なデータ構造とは対照的にどのように使用されることを意図しているかという主題について、少し考えることで大きな恩恵を受けることができると確信しています。

4

4 に答える 4

2

私には、SQL でデータを構造化する方法と構造化する方法の微妙な点は、よりあいまいなトピックのように思えます。

これは「データ (ベース) モデリング」と呼ばれ、工学分野と芸術の間のどこかにあります (多くのコンピューター プログラミングと同様)。このトピックに本当に興味がある場合は、ERwin Methods Guideをご覧ください。

私が自分自身のために自動的に描いている構造体の配列のアナロジーはどこで壊れますか?

永続性、同時実行性、一貫性、およびスケーラビリティ。

  • 永続性: テーブルは永続ストレージに自動的に保存されます。明示的に削除するか、壊滅的なハードウェア障害が発生するまで、そこに残り、再起動後も存続します (実際のデータベース サーバーが再起動することはほとんどありません)。DBMS には、後者の場合に役立つ十分に油を注いだバックアップ手順があります。
  • 同時実行性 : テーブルは、多くのクライアントが同時にアクセスし、(必要に応じて) 変更することを意図しています。ロックや複数バージョンの同時実行制御などのメカニズムを使用して、クライアントが「お互いに足を踏み入れる」ことがないようにします。
  • 一貫性: 特定の制約(一意性、外部キー、チェックなど)を定義でき、DBMS はそれらが決して壊れないようにします。さらに、これは多くの場合、宣言的な方法で実行できるため、エラーの可能性を最小限に抑えることができます。その上、データベースで行うことはすべてトランザクションであるため、原子性、一貫性、分離、耐久性 (別名「ACID」 ) の利点を享受できます。簡単に言えば、データベースは不正なデータから身を守ります。
  • スケーラビリティ: 適切に設計されたデータベース スキーマは、使用可能な RAM の範囲を超えて大きくなり、インデックス作成、パーティション分割、クラスタリングなどの手法を使用して良好なパフォーマンスを維持できます。さらに、SQL は宣言的でセットベースです。つまり、 DBMS には、目前のデータに最適な「クエリ実行計画」を選択する、クエリを自動並列化する、結果が再利用されることを期待して結果をキャッシュするなど、クエリの意味を変更することなく許容範囲があります。
于 2012-11-09T03:35:47.457 に答える
2

構造体の配列への類推は悪くありません...最初は。

この開始後、データの編成に関して違いが始まります。データベース関係者は、「正規形」の法則が大好きです。これらの法則は、C++ や同様のプログラミング言語にはありません。これらの法則に従ってテーブル内のデータを編成することで、データベース エンジンは魔法 (クエリ、結合) をより適切に実行できます。つまり、データベースをコンパクトに保ち、何百万行も一瞬で処理し、複数のリクエストを同時に実行できます。それらは絶対的な法則ではありません。99.9999% のケースで 1NF (第 1 正規形) に従いますが、数値が大きいほど (2NF、3NF など)、DB プランナーがそれらから逸脱することを許容することが多くなります。

通常のフォームの説明は、たとえばhere にあります

あなたの例の違いを説明しようとします。

あなたの例では、構造体のフィールドはデータベーステーブルの列に対応しています。名前のベクトルを構造体の新しいフィールドとして追加することは、名前のコンマ区切りリストをテーブルの新しい列に追加することに相当します。これは、値のリストではなく、1 つのセルが 1 つの値であることを要求する 1NF に違反しています。データを正規化するには、2 つの配列が必要です。1 つは Person 構造体、もう 1 つは Child の新しい構造体です。C++ ではポインタだけを使用して各子をその親にリンクできますが、SQL ではキーのメカニズムを使用する必要があります。Person 構造体に id フィールドを追加しました。ここで、ParentId フィールドを Child 構造体に追加して、データベース エンジンが親を見つけられるようにする必要があります。ParentId 列は外部キーと呼ばれます。子供用の新しいテーブル/構造体を作成する代わりに 1NF を満たすもう 1 つのアプローチは、子供中心の考え方に切り替えて、子の親に関するすべての情報を含む、子ごとのレコードを持つテーブルを 1 つだけ持つことです。親に関する情報は、明らかに、この親が持つ子の数と同じ数のレコードで繰り返されます。

注 (これは 1NF の一部とも見なされます) 構造体の配列では要素の順序が常にわかっていますが、データベースではレコードを格納する順序はエンジン次第です。これは単なる数学的な順序付けられていないレコードのセットであり、エンジンはそれを内部ストレージに再分類して、さまざまな最適化を行うことができます。データベースから SELECT ステートメントでレコードを取得する場合、順序が重要な場合は ORDER BY 句を指定する必要があります。

2NF とは、記録から繰り返しを取り除くことです。Person 構造体の一部として、職場に関連するフィールドもあると想像してください。会社の名前と会社の住所が含まれていると想像してください。データセット内の多くの人が同じ会社で働いている場合、レコードで会社の住所を繰り返すことになります。おそらく、C++ でもこれらの繰り返しを行うことはありませんが、それでもこれらの繰り返しを別のテーブルに抽出すると、2NF が満たされます。厳密に言えば、繰り返しがなく、すべての人が異なる場所で働いている場合でも、2NF では、1 つのテーブルが 1 つのエンティティを表す必要があるため、職場に関するデータを別のテーブルに抽出する必要があります。

3NF は推移的な依存関係の除去に関するものであり、一種のオプションと見なされるため、ここでは説明しません。上記のリンクを参照してください。

C++ でのデータ構造の従来のプログラミングとはまったく異なるデータベースのもう 1 つの機能は、データベース インデックスです。簡単に言うと、インデックスは 1 つまたは複数の列 (つまり、垂直方向のスライス) を別のテーブルにコピーしたものに過ぎず、そこで固有の順序で格納され、インデックス内の各レコードはレコード全体への参照を保持します。したがって、高さでインデックスを作成する例では、新しい 64 個の要素の別の配列を作成します

struct HeightIndexElem
{
    double height;
    Person* pFullRecord;
}

この配列の高さで並べ替えます。これにより、DB エンジンは特定のクエリを自動的に最適化できます。データベース エンジン自体が、特定のインデックスをいつ使用するかを決定します。C++ では通常、マップ (C# では辞書) を作成して、特定の特性による要素の検索を高速化しますが、これらのマップを自分で使用する必要があります - 自動的な側面はありません。

于 2012-11-09T06:04:38.057 に答える
1

大きな違いがあります:-

  • SQL テーブルは永続的です -- (英語 Tran: ディスクに書き込まれます)
  • それらはトランザクションです-(実際にはディスクに書き込まれます)
  • それらは任意のサイズにすることができます -- (数億行のテーブルは非常に一般的です)
  • リレーショナル代数をサポートします -- (他のテーブルとの結合、フィルタリングなど)
  • リレーショナル代数は証明可能です -- 特定の SELECT ステートメントに対して、可能な正解は 1 つだけです。

最大の違いは、"UPDATE" と "COMMIT" を行うと、データがデータベースに保存され、"DELETE" を決定するまでそこにあることがわかります。配列内の構造を更新すると、マシンの電源がオフになると失われます。

もう1つの大きな違いはスケールです。最新の DBMS のサイズは、ハード ディスクの予算によってのみ制限されます。

于 2012-11-09T03:10:47.937 に答える