Mysql

不尋常的關係,二元方面

  • April 10, 2015

我對數據庫有非常不尋常的問題。我不是一個很好的英語演講者,但很好的英語閱讀者:) 所以為了解釋,我會給你例子。

第1部分

在 MySQL 中,我有兩個表的關係我無法像主外鍵一樣執行。向前說,這是一些“一對多”的關係。這是表格的範例:

#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值對於 all 可能是相同的Types,但是第二個表中描述的含義是不同的。

#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”的位(不包括零位)都與 #2 的列相關CVbits,並且Type. Type在 #1 和 #2 中 - 同樣的事情。所以:

ConcVal = 14 ( 111 0) 與 CVbits {1;2;3} 相關聯;

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

ConcVal = 12 ( 110 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

Part2(非常小)

我知道上面描述的邏輯更好地在前端實現,但我想測試可以提供多少 DBMS,所以我寫了UDF getCVbits,稱為left join with 子句。因此,按照您的目的,該查詢執行時間過長。300~3000 行的時間接近 1,2~2,0 秒。我猜,UDF 太慢了。但如果你願意,我想我可以給你真正的詢問。ConcVal``“,1,2,”,``“where getCVbits (a.ConcVal) LIKE concat(‘%,’b.CVbits,’,%’)”

第三部分

如果我將編寫用於getCVbits計算所需字元串的插入和更新觸發器怎麼辦。這個字元串我可以儲存在#1 中。這允許查詢更快,但不利於數據規範化。

題:

Q1。儲存計算的 bitorderstring 是好方法還是讓使用者稍等一下?=)(我想,結果集會比我測試的要多得多)

Q2。如果使用,我如何StatesDescriptions沒有 LIKE 運算符的情況下加入getCVbits?實際上,我可以從 UDF 返回任何我需要的東西。

Q3。還有另一種實現表之間“關係”的方法……數據嗎?

更新: 所以,就像我承諾的那樣,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

當我使用 UDF 和LIKE.

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

Q1。儲存計算的 bitorderstring 是好方法還是讓使用者稍等一下?=)(我想,結果集會比我測試的要多得多)

MySQL 支持位類型的列。正如您所期望的那樣,它們每個只使用一個位,以 8 個為一組。這將提供與您目前獲得的相同的磁碟和記憶體密度,但查詢編寫更容易。

Q2。如果使用 getCVbits,如何在沒有 LIKE 運算符的情況下將狀態加入描述?實際上,我可以從 UDF 返回任何我需要的東西。

@Rick 有它:你需要在tblDescriptions.CVbits. 一個更簡單(執行時更快)的解決方案是製作CVBits一個整數並儲存二進制等效值(1、2、4、8、16),然後使用二進制 AND 運算符ConcVal連接。CVBits

Q3。還有另一種實現表之間“關係”的方法……數據嗎?

是的。規範您的設計。 ConcVal打破第一個範式,因為它包含許多值。創建一個僅包含tblStates.ID和的新表tblDescriptions.ID

請不要在表名前加上“tbl”前綴。

引用自:https://dba.stackexchange.com/questions/97353