8

データベース内の情報をすばやく調査する良い方法は、すべてのテーブルとテーブル間のすべての関係のデータベース ダイアグラムを自動的に作成するツールを適用することです。

私の経験では、そのようなツールは関係として外部キーを使用しますが、私が試したほとんどのデータベースには含まれていません。確かに、それらは外部キーに対応する制約を満たしますが、それらを強制しません。そして、関連のない一連のテーブルからなる「ダイアグラム」が完成します。

だから私が探しているのは、「宣言されていない外部キー」を計算できるソフトウェアであり、

  • それらをデータベース ダイアグラムのテーブル リレーションとして使用する、または
  • 対応する外部キー宣言の SQL コードを生成します

可能であれば無料で、すでにこれを行うことができるツールを知っていますか?

4

4 に答える 4

6

興味深い質問です。データベースのスキーマとデータを解析して、関係を厳密に定義せずに、どのテーブルが関連しているか、または相互に関連する必要があるかを判断しようとしています。実際には、関係を推測しようとしています。

このような関係を推測する方法は 2 つあります。まず、使用しているデータベースによってアプローチが異なる可能性があることを言わせてください。いくつかの疑問が頭に浮かびます(答えたくありませんが、考える価値はあります)

  • これらの社内エンタープライズ システムは、一貫した命名規則またはパターンに従っていますか?
  • それとも、いつでもどこでも出くわす「野生の」データベースですか?
  • どのような仮定を立てる準備ができていますか?
  • 結果で偽陽性または偽陰性のどちらを取得したいですか?

このタイプの推論は、ほぼ確実に誤った結果をもたらし、多くの仮定に基づいて構築されていることに注意してください。

そこで、私が協調して使用する 2 つのアプローチを紹介します。

構造・命名による関係の推測(記号解析)

一般的なデータベース設計では、テーブル名の後に PK 列の名前を付けるか (たとえばCustomerId、テーブル上Customer)、または単に PK 列に名前を付けますId

別のテーブルとの FK リレーションシップを持つテーブルは、多くの場合、その関連列に関連テーブルと同じ名前を付けます。Orderテーブルでは、テーブルの/列CustomerIdを参照する列が必要です。CustomerIdIdCustomer

このタイプの分析には以下が含まれます。

  • 同様のフレーズ/単語についてテーブル全体の列を検査する
  • 他のテーブルの名前に似た列名を探す
  • 他の列の名前を含む列名のチェック (例FirstCustomerId&SecondCustomerId両方ともテーブルCustomerId内の列を参照)Customer

データから関係を推測する(統計分析)

コメントで行ったことを示唆しているように、データを見ると、「可能な」参照を判断できます。テーブルの列に存在しない値がテーブルの列に含まれCustomerIdている場合、これが有効な関係であるかどうかを疑問視するのは理にかなっています (ただし、わかりません!)OrderIdCustomer

データ分析の簡単な形式は、日付と時刻を使用することです。互いに近接して作成された行は、互いに関連している可能性が高くなります。作成されたすべてのOrder行に対して、数秒以内に作成された 2 ~ 5 行が存在する場合は、2 つItemの行の間に関係がある可能性があります。

より詳細な分析では、使用された値の範囲と分布を調べることができます。

たとえば、OrderテーブルにSt_Id列がある場合、シンボリック分析を使用して、その列がStateテーブルまたはテーブルのいずれかに関連している可能性が高いと推測できStatusます。列には 6 つのSt_Id離散値があり、レコードの 90% が 2 つの値でカバーされています。Stateテーブルには 200 行あり、テーブルStatusには 9 行あります。St_Id列がテーブルに関連していると非常に合理的に推測できますStatus。これにより、テーブルの行をより広くカバーできます (行の 2/3 が「使用」されますが、Stateテーブル内の行の 3% のみが使用されます)。 )。

既存のデータベースでデータ分析を実行して「実際のデータ」を収集する場合、構造推論のガイドとして使用できるいくつかのパターンが期待できます。多数のレコードを含むテーブルに、少数の値が何度も繰り返される列がある場合 (必ずしも順序どおりである必要はありません)、この列は、対応する少数の行を持つテーブルに関連している可能性が高くなります。

要約すれば

幸運を祈ります。これは興味深い問題です。私はいくつかのアイデアを投げかけましたが、これは試行錯誤、データ収集、およびパフォーマンス チューニングの状況です。

于 2011-08-22T03:48:45.180 に答える
5

これは、ほとんどの場合、重要な作業です。幸運にも、Ruby on Rails や CakePHP などの最新のフレームワークのスキーマを分析でき、開発者が列の規則に従うことに厳密に取り組んでいる場合は、すべてではないが多くのスキーマを見つける合理的な可能性があります。 、暗黙の関係の。

つまり、テーブルがテーブルuser_id内のエントリを参照するような列を使用している場合users

注意: 一部のエンティティ名は不規則に複数形になる場合があり(entity良い例: entities, not entitys)、これらはキャッチするのが困難です (ただし、可能性はあります)。admin_idただし、開発者が users テーブルに参加するキーなどはuser.id推測できません。これらのケースは手動で処理する必要があります。

あなたは RDBMS を指定していませんでしたが、私は MySQL をよく使用しており、現在この問題に取り組んでいます。

次の MySQL スクリプトは、列名によって暗示されるほとんどの関係を推測します。次に、テーブル名を見つけることができなかったリレーションシップを一覧表示するので、少なくともどれが欠けているかがわかります。推測された親と子が、単数形と複数形の名前、および暗黙の関係とともにリストされます。

-- this DB is where MySQL keeps schema information
use information_schema;

-- change this to the DB you want to analyse
set @db_name = "example_DB";

-- infer relationships 
-- NB: this won't catch names that pluralise irregularly like category -> categories or bus_id -> buses etc.
select  LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME) - 3 )              as inferred_parent_singular
,       CONCAT(LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME) - 3 ),"s")  as inferred_parent_plural 
,       C.TABLE_NAME                                                  as child_table
,       CONCAT(LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME)-3), "s has many ", C.TABLE_NAME) as inferred_relationship
from    COLUMNS C
JOIN    TABLES T on C.TABLE_NAME = T.TABLE_NAME 
        and C.TABLE_SCHEMA = T.TABLE_SCHEMA 
        and T.TABLE_TYPE != "VIEW"  -- filter out views; comment this line if you want to include them
where   COLUMN_NAME like "%_id"     -- look for columns of the form <name>_id
and     C.TABLE_SCHEMA = T.TABLE_SCHEMA and T.TABLE_SCHEMA = @db_name 
-- and     C.TABLE_NAME not like "wwp%"  -- uncomment and set a pattern to filter out any tables you DON'T want included, e.g. wordpress tables e.g. wordpress tables
-- finally make sure to filter out any inferred names that aren't really tables
and     CONCAT(LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME) - 3 ),"s") -- this is the inferred_parent_plural, but can't use column aliases in the where clause sadly
          in (select TABLE_NAME from TABLES where TABLE_SCHEMA = @db_name)
;

これにより、次のような結果が返されます。 ここに画像の説明を入力

次に、次の方法で検出された命名規則の例外を調べることができます。

-- Now list any inferred parents that weren't real tables to see see why (irregular plurals and columns not named according to convention)
select  LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME) - 3 ) as inferred_parent_singular
,       CONCAT(LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME) - 3 ),"s") as inferred_parent_plural 
,       C.TABLE_NAME as child_table
from    COLUMNS C
JOIN    TABLES T  on  C.TABLE_NAME    = T.TABLE_NAME 
                  and C.TABLE_SCHEMA  = T.TABLE_SCHEMA 
                  and T.TABLE_TYPE   != "VIEW"            -- filter out views, comment this line if you want to include them
where   COLUMN_NAME like "%_id"
and     C.TABLE_SCHEMA = T.TABLE_SCHEMA and T.TABLE_SCHEMA = @db_name 
-- and     C.TABLE_NAME not like "wwp%"  -- uncomment and set a pattern to filter out any tables you DON'T want included, e.g. wordpress tables e.g. wordpress tables
-- this time only include inferred names that aren't real tables
and     CONCAT(LEFT(COLUMN_NAME, CHAR_LENGTH(COLUMN_NAME) - 3 ),"s")
          not in (select TABLE_NAME from TABLES where TABLE_SCHEMA = @db_name)
;

これにより、手動で処理できる次のような結果が返されます。 ここに画像の説明を入力

これらのスクリプトを変更して、必要に応じて外部キー作成ステートメントを含めて、便利なものを吐き出すことができます。ここで、最後の列は単純な「has many」関係ステートメントです。これは、非常に単純な構文 (「pidgin」と呼ばれる) で記述された関係ステートメントに基づいて、その場で関係図を描画する高速モデリング ツールである pidgin と呼ばれる、私が作成したツールで使用します。http://pidgin.gruffdavies.comで確認できます。

上記のスクリプトをデモ DB で実行して、期待できる結果を示しました。

ここに画像の説明を入力

私はスクリプトで不規則な複数形に対応していませんが、少なくとも -y で終わるエンティティの場合は、それも試してみるかもしれません。自分で試してみたい場合は、<name>_id列名をパラメーターとして取り、その_id部分を取り除き、ヒューリスティックを適用して正しく複数形にするストアド関数を作成することをお勧めします。

それが役に立つことを願っています!

于 2014-08-29T12:13:30.690 に答える
0

必要なものを検索するのに役立つソフトウェアについては知りませんが、次のクエリは、開始するのに役立ちます。現在のデータベース内のすべての外部キー関係が一覧表示されます。

SELECT
    K_Table = FK.TABLE_NAME,
    FK_Column = CU.COLUMN_NAME,
    PK_Table = PK.TABLE_NAME,
    PK_Column = PT.COLUMN_NAME,
    Constraint_Name = C.CONSTRAINT_NAME
FROM
    INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
            SELECT
                i1.TABLE_NAME,
                i2.COLUMN_NAME
            FROM
                INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
            INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
                ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
            WHERE
                i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
           ) PT
    ON PT.TABLE_NAME = PK.TABLE_NAME

お役に立てれば。

于 2011-08-21T10:46:53.753 に答える