データベースに関して非常に珍しい質問があります。私は英語が上手ではありませんが、英語が上手です:)説明のために例を挙げましょう。
パート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演算子なしでDescriptions
をgetCVbits
に結合するにはどうすればよいですか?実際、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演算子を使用してConcVal
をCVBits
に結合することです。
_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
を使用する場合は秒。
WHERE (1 << CVbits) & ConcVal
AND CVbits != 0 -- (to "exclude the zero bit")
Q1。計算されたbitorderstringを保存するのは良い方法ですか、それともユーザーに少し待たせますか? =)(おそらく、結果セットは私がテストしたよりもはるかに多くなるでしょう)
MySQLはビットタイプの列をサポートしています。ご想像のとおり、これらは8セットでそれぞれ1ビットのみを使用します。これにより、現在取得しているのと同じディスクとメモリの密度が得られますが、クエリの記述がはるかに簡単になります。
Q2。 getCVbitsを使用している場合、LIKE演算子を使用せずに状態を説明に結合するにはどうすればよいですか?実際、UDFから必要なものは何でも返すことができます。
@Rickあります:tblDescriptions.CVbits
でバイナリ計算を行う必要があります。より簡単な(実行時の速度が速い)解決策は、CVBits
を整数にして、バイナリに相当する値(1、2、4、8、16)を格納し、バイナリAND演算子を使用してConcVal
をCVBits
に結合することです。
Q3。テーブル...データ間の「関係」を実装する別の方法はありますか?
はい。デザインを正規化します。 ConcVal
は、多くの値を保持しているため、最初の正規形を破ります。 tblStates.ID
とtblDescriptions.ID
のみを含む新しいテーブルを作成します。
また、テーブル名の前に「tbl」を付けるのはやめてください。