web-dev-qa-db-ja.com

異常な関係、二項関係

データベースに関して非常に珍しい質問があります。私は英語が上手ではありませんが、英語が上手です:)説明のために例を挙げましょう。

パート1

MySQLには、主外部キーのように実行できなかったリレーションを持つ2つのテーブルがあります。前向きに言えば、これは「1対多」の関係です。これはテーブルの例です:

_#1 – States
ID      ConcVal    Type     Time
1        14        1        05:30
2        13        1        06:30
3        10        2        07:00
4        13        2        08:50
5        10        2        09:00
6        13        2        09:40
_

ConcValは15以下です(バイナリでは111 1)(実際には32ビットか、将来的にはそれ以上になる可能性がありますが、質問を簡単にするために4ビットのみです)。 ConcVal-バイナリでのDescriptionsの重ね合わせのようなものです。したがって、ConcValの値はすべてのTypesで同じである可能性がありますが、2番目の表で説明されている意味は異なります。

_#2 - Descriptions
ID  Type    CVbits  Description
1   1       0       Some text for `type` 1
2   1       1       Some other text
3   1       2       Some other text
4   1       3       Some last text for type 1
5   2       0       Some text for type 2
…
8   2       3       Some last text for `type` 2
_

ConcVal値のバイナリ表現によるデータ間の関係:「1」(ゼロビットを除く)のすべてのビットは、列CVbitsおよびTypeによる#2のコルテッジに関連しています。 #1と#2のType-同じこと。そう:

ConcVal = 14(111 0)は、CVbits {1; 2; 3};のコルテッジに関連しています。

ConcVal = 13(11 1)>> CVbits:{2; 3};

ConcVal = 12(11 0)>> CVbits:{2; 3}。

テーブルについて話す場合、次の架空の(実際には私がやった)参加は私のニーズを理解するのに役立ちます:

_StateID     Type    ConcVal     (bin)       CVbits  DescrID
    1       1       14          (1110)      1       1
    1       1       14          (1110)      2       2
    1       1       14          (1110)      3       3
    …
    6       2       13          (1100)      2       6
    …
    6       2       13          (1100)      3       8
_

パート2(非常に小さい)

上記のロジックはフロントエンドでより適切に実装できることを知っていますが、DBMSをどれだけ提供できるかをテストしたいので、getCVbitsと呼ばれるUDFを作成しました。これは、ConcValのビットの位置番号を含む文字列(このbitorderstringと呼びます)を返します。 _“,1,2,”,_およびクエリ左結合と句“where getCVbits (a.ConcVal) LIKE concat(‘%,’b.CVbits,’,%’)”。したがって、目的に応じて、そのクエリの実行時間が長すぎます。 300〜3000行で1,2〜2,0秒に近い値。 UDFは遅すぎると思います。しかし、あなたが望むなら、私はあなたに本当の質問をすることができると思います。

パート

getCVbitsで使用される挿入トリガーと更新トリガーを記述し、必要な文字列を計算するとどうなりますか。この文字列は#1に保存できます。これにより、クエリがはるかに高速になりますが、データの正規化には反します。

質問:

Q1。計算されたbitorderstringを保存するのは良い方法ですか、それともユーザーに少し待たせますか? =)(おそらく、結果セットは私がテストしたよりもはるかに多くなるでしょう)

Q2。 Statesを使用する場合、LIKE演算子なしでDescriptionsgetCVbitsに結合するにはどうすればよいですか?実際、UDFから必要なものは何でも返すことができます。

Q3。テーブル...データ間の「関係」を実装する別の方法はありますか?

PDATED:つまり、私が約束したように、2つのクエリの結果:

_SELECT
    b.ID AS StatusID,
    b.Type as Type,
    b.CVTime AS CVTime,
    b.ConcVal AS ConcVal,
    CONV(b.ConcVal, 10, 2) AS BinStr,
    a.ID AS DescrID,
    a.CVbits AS CVbits,
    a.Description AS Description
FROM
    (Reasons a
    JOIN States b ON ((a.Type = b.Type)))
_

および#1

_WHERE
    (a.CVbits <> 0)
        AND (a.CVbits <> 8)
        AND (a.CVbits <> 16)
        AND (1 << a.CVbits) & b.ConcVal
_

および#2

提案されたリックジェームスのように:

より簡単な(実行時の速度が速い)解決策は、CVBitsを整数にして、バイナリに相当する値(1、2、4、8、16)を格納し、バイナリAND演算子を使用してConcValCVBitsに結合することです。

_WHERE
    (a.CVbits <> 0)
        AND (a.CVbits <> 8)
        AND (a.CVbits <> 16)
        AND (a.CV & b.ConcVal)
_

返される最大4280行でそれほど違いはありません(期間/フェッチ):

_#1 (1<<CVbits & ConcVal)    #2 (CV & ConcVal)
0.016 sec / 0.421 sec       0.015 sec / 0.687 sec
0.016 sec / 0.156 sec       0.000 sec / 0.296 sec
0.031 sec / 0.234 sec       0.016 sec / 0.171 sec
0.016 sec / 0.218 sec       0.016 sec / 0.359 sec
0.016 sec / 0.172 sec       0.016 sec / 0.125 sec
_

代わりに(1.794秒/ 78.235)UDFとLIKEを使用する場合は秒。

2
brz
WHERE (1 << CVbits) & ConcVal
  AND CVbits != 0    -- (to "exclude the zero bit")
1
Rick James

Q1。計算されたbitorderstringを保存するのは良い方法ですか、それともユーザーに少し待たせますか? =)(おそらく、結果セットは私がテストしたよりもはるかに多くなるでしょう)

MySQLはビットタイプの列をサポートしています。ご想像のとおり、これらは8セットでそれぞれ1ビットのみを使用します。これにより、現在取得しているのと同じディスクとメモリの密度が得られますが、クエリの記述がはるかに簡単になります。

Q2。 getCVbitsを使用している場合、LIKE演算子を使用せずに状態を説明に結合するにはどうすればよいですか?実際、UDFから必要なものは何でも返すことができます。

@Rickあります:tblDescriptions.CVbitsでバイナリ計算を行う必要があります。より簡単な(実行時の速度が速い)解決策は、CVBitsを整数にして、バイナリに相当する値(1、2、4、8、16)を格納し、バイナリAND演算子を使用してConcValCVBitsに結合することです。

Q3。テーブル...データ間の「関係」を実装する別の方法はありますか?

はい。デザインを正規化します。 ConcValは、多くの値を保持しているため、最初の正規形を破ります。 tblStates.IDtblDescriptions.IDのみを含む新しいテーブルを作成します。

また、テーブル名の前に「tbl」を付けるのはやめてください。

1
Michael Green