簡體   English   中英

MySQL:Joins與Bitwise運算符及其性能

[英]MySQL: Joins vs. Bitwise operator, and performance thereof

關於此主題有很多問題,但是我的問題更着重於性能問題。

關於一個對象,我想跟蹤多個“屬性”,每個屬性都有多個離散的“值”(每個屬性具有3到16個有效“值”。)例如,考慮跟蹤軍事人員。 屬性/值可能是(不是真實的,我完全把它們編成了):

屬性:{values}
languages_spoken: {english, spanish, russian, chinese, …. }
certificates: {infantry, airborne, pilot, tank_driver…..}
approved_equipment: {m4, rocket_launcher, shovel, super_secret_radio_thingy….}
approved_operations: {reconnaissance, logistics, invasion, cooking, ….}
awards_won: {medal_honor, purple_heart, ….}

… 等等。

一個要執行此操作的方式-我要執行此操作的方式 -是擁有人員表和屬性表:

personnel table => [id, name, rank, address…..]
personnel_attributes table => [personnel_id, attribute_id, value_id]

以及相關的屬性和值表。

因此,如果pesonnel_id = 31415被批准用於后勤,則person_attributes表中將包含以下條目:

personnel_id | attribute_id | value_id
31415 | 3 | 2

其中3 =“ approved_operations”的attribute_id和2 =“ logistics”的value_id(抱歉,格式空間未對齊。)

然后,查找所有會說英語或西班牙語,步兵或機載,並能操作鏟子或super_secret_radio_thingy的人員,可能會像這樣:

SELECT t1.personnel_id FROM personnel_attributes t1, personnel_attributes t2, personnel_attributes t3
WHERE ((t1.attribute_id = 1 and t1.value_id = 1) OR (t1.attribute_id = 1 and t1.value_id = 2))
AND ((t2.attribute_id = 2 and t1.value_id = 1) OR (t2.attribute_id = 2 and t1.value_id = 2))
AND ((t3.attribute_id = 3 and t1.value_id = 3) OR (t3.attribute_id = 3 and t1.value_id = 4))
AND t2.personnel_id = t1.personnel_id
AND t3.personnel_id = t1.personnel_id;

假設這不是編寫SQL查詢的完全愚蠢的方法,問題在於它非常慢(即使具有看似相關的索引)。

因此,我想使用按位運算符代替,其中每個屬性是表中的一列,每個值都是一個位。 相同的搜索將是:

SELECT personnel_id FROM personnel_attributes
WHERE language & b'00000011'
AND certificates & b'00000011'
AND approved_operations & b'00001100';

我知道這會進行全表掃描,但是在我的350,000個樣本人員的實驗中,每個人都有16個屬性,第一種方法花了20秒,而按位方法花了38毫秒!

我在這里做錯什么了嗎? 這些是我應該期待的性能結果嗎?

謝謝!

使用django-bitfield或使用單獨的表進行標記存在相同的問題。

受您的實驗啟發,我使用了一個3.5m的記錄表(innodb)並進行了count()並檢索這兩個變量的查詢。 結果令人驚訝:大約5秒和40秒的位域勝利。

使用按位運算將需要評估所有行。 我相信可以通過更改原始SELECT語句以及如何調整表來解決您的問題:

為了更易於閱讀,我將屬性值更改為單詞而不是整數,因此在閱讀示例時不會造成混淆,但是顯然您可以將它們保留為整數,並且該概念仍然有效:

CREATE TABLE PERSONNEL (
    ID INT,
    NAME VARCHAR(20)
)

CREATE TABLE PERSONNEL_ATTRIBUTES (
    PERSONNEL_ID INT,
    ATTRIB_ID INT,
    ATTRIB_VALUE VARCHAR(20)
)

INSERT INTO PERSONNEL VALUES (1, 'JIM SMITH')
INSERT INTO PERSONNEL VALUES (2, 'JANE DOE')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (1, 1, 'English')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (1, 1, 'Spanish')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (1, 1, 'Russian')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (1, 3, 'Logistics')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (1, 3, 'Infantry')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (2, 1, 'English')
INSERT INTO PERSONNEL_ATTRIBUTES VALUES (2, 3, 'Infantry')

SELECT P.ID, P.NAME, PA1.ATTRIB_VALUE AS DESIRED_LANGUAGE, PA2.ATTRIB_VALUE AS APPROVED_OPERATION
FROM PERSONNEL P
JOIN PERSONNEL_ATTRIBUTES PA1 ON P.ID = PA1.PERSONNEL_ID AND PA1.ATTRIB_ID = 1
JOIN PERSONNEL_ATTRIBUTES PA2 ON P.ID = PA2.PERSONNEL_ID AND PA2.ATTRIB_ID = 3
WHERE PA1.ATTRIB_VALUE = 'Spanish' AND (PA2.ATTRIB_VALUE = 'Infantry' OR PA2.ATTRIB_VALUE = 'Airborne')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM