我正在一个网站上工作,用户可以获得有关其个人资料(user_name,电子邮件,偏好等)的核心数据以及可能随时更改的任意数据。并非所有用户都需要所有数据字段。因此,在我的tblUsers MySQL表中,我不想添加一堆可能只对少数用户有用的列。
我想象的方法是创建第二个表,其中包含以下列: UID INT,dataType TINYINT,dataValue INT
基本上UID会指向users表中的用户ID(tlbUsers),而dataType会指向dataTypes列表(另一个表)中的ID,例如“Age”,“Favorite Color”,“Points”等等。
问题是,当我说: “SELECT * FROM tblUsers,tblData WHERE UID = ID” 我得到几排堆叠(效果很好......) 但我无法弄清楚如何编写一个考虑tblData信息的查询。
例如,假设我要选择所有21岁且分数在400-500之间的用户。
如果它们是实际的列,我会说:
SELECT * FROM tblUsers, tblData, WHERE UID=ID AND dataAge = 21 AND dataScore >= 400 AND dataScore <= 500
但是,我不能这样做,因为dataAge和dataScore不是列 - 它们是dataTable中的行,如下所示:
UID dataType dataValue
35 1 21 //user #35's age (dataType 1)
35 2 467 //user #35's score (dataType 2)
49 1 21
49 2 491
我无法预测将来需要哪些数据类型。 用户可以随意添加关于他们自己的数据类型,并非所有用户都会同时拥有所有可能的数据类型。
我想也可以使用另一个表,用于文本数据,格式相同,UID,dataType,dataString。
让我说我写
SELECT * FROM tblUsers, tlbData, WHERE UID=ID AND dataType=1 AND dataValue=21 AND dataType=2 AND dataValue >= 400 AND dataValue <= 500
因为我想比较年龄和分数,所以dataType和dataValue在同一个调用中都会被模糊地使用...
我的问题:满足我需求的最佳表格结构是什么?如何正确查询我当前的设置?
答案 0 :(得分:0)
用户必须满足查询中的所有条件,因此您必须多次加入tblData
,就像多个表一样:
SELECT u.*
FROM tblUsers u
JOIN tblData d1 ON d1.uid = u.id AND d1.dataType=1 AND d1.dataValue=21
JOIN tblData d2 ON d2.uid = u.id AND d2.dataType=2
AND d2.dataValue BETWEEEN 400 AND 500
要获得高效率,索引至关重要。在特殊情况下,您可能需要以下索引:
CREATE INDEX tbldata_uid_idx ON tblData(uid);
CREATE INDEX tbldata_datatype_datavalue_idx ON tblData(dataType, dataValue);
我认为id
是tblUsers
的主键,并且会自动编入索引。
了解multi-column indexes in the manual。
JOIN性能最近有所增加,但仍然缺乏其他数据库系统,如Oracle,SQL Server或PostgreSQL,其中JOIN处理非常高性能。 MySQL不是许多JOIN和子查询的最佳选择。
对于您的特定情况(可以组合的多个连接),位图索引扫描将提供最佳性能 - 这是MySQL中不存在的功能。它有一个“index_merge”功能,所以替代它。