繁体   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