我有一个包含许多列的用户表,它看起来大致如下:
dname: { type: string(255), notnull: true }
email: { type: string(255), notnull: true, unique: true }
email_code: { type: string(255) }
email_confirmed: { type: boolean, default: false }
profile_filled: { type: boolean, default: false }
password: { type: string(255), notnull: true }
image_id: { type: integer }
gender: { type: enum, values: [male, female] }
description: { type: string }
dob: { type: date }
height: { type: integer(3) }
looks: { type: enum, values: [thin, average, athletic, heavy] }
looking_for: { type: enum, values: [marriage, dating, friends] }
looking_for_age1: { type: integer }
looking_for_age2: { type: integer }
color_hair: { type: enum, values: [black, brown, blond, red] }
color_eyes: { type: enum, values: [black, brown, blue, green, grey] }
marital_status: { type: enum, values: [single, married, divorced, widowed] }
smokes: { type: enum, values: [no, yes, sometimes] }
drinks: { type: enum, values: [no, yes, sometimes] }
has_children: { type: enum, values: [no, yes] }
wants_children: { type: enum, values: [no, yes] }
education: { type: enum, values: [school, college, university, masters, phd] }
occupation: { type: enum, values: [no, yes] }
country_id: { type: integer }
city_id: { type: integer }
lastlogin_at: { type: timestamp }
deleted_at: { type: timestamp }
我创建了一个包含大多数字段(枚举,国家/地区,城市)的表单,这些字段允许用户根据他们选择的字段生成where语句。因此,如果有人选择了抽烟:no和country_id:7那么sql where语句可能如下所示:
SELECT id
FROM user u
WHERE u.deleted_t IS NULL AND u.profile_filled IS NOT NULL AND smokes = 'no' AND country_id = 7;
因为用户可以选择要过滤的任何字段组合,所以我不确定如何对此表进行索引,我是否应该在所有可以过滤的字段上创建单个列索引?你会提出什么建议?
答案 0 :(得分:0)
每个可搜索字段都需要拥有单列索引。如果您的表很大并且搜索条件没有索引,则必须扫描每一行。
添加一个新用户会比较慢,但是你描述你的情况我会想象你的查询主要是选择一些插入。
答案 1 :(得分:0)
我在工作中有同样的事情,很多列和1000种不同的选择方式。这是一场噩梦。但我确实发现,经常使用某些过滤器组合。我会创建索引并留下其他很少用于缓慢运行的索引。在MSSQL中,我可以运行一个查询来向我展示针对数据库运行的最昂贵的查询,mySQL应该有类似的东西。一旦我拥有它们,我就会创建一个覆盖列的索引来加速它们。最终,你将获得90%的保障。除非我有一把AK47指着我,否则我个人绝不会再设计一张这样的桌子。 (我的索引比表中的数据大3倍,如果你需要添加一堆或记录,这个数据非常不酷)。 我不知道如何重新设计表格,我的第一个想法是将表格分成两部分,但这会增加其他地方的头痛。
用户表(UserID,名称)
1, Lisa
2, Jane
3, John
用户属性表(UserID,AttributeName,AttributeValue)
1, EYES, Brown
1, GENDER, Female
2, EYES, Blue
2, GENDER, Female
3 EYES, Blue
3, GENDER, Male
这样可以更快地识别属性,但不会使您的查询直接写入。
SELECT UserID, COUNT(*) as MatchingAttributes
FROM UserAttributes
WHERE (UserAttributes.AttributeName = 'EYES' AND UserAttributes.AttributeValue = 'Blue') OR
(UserAttributes.AttributeName = 'GENDER' AND UserAttributes.AttributeValue = 'Female')
这应该返回以下
UserID, MatchingAttributes
1, 1
2, 2
3, 1
然后,您需要执行的操作是在查询中添加HAVING COUNT(*)= 2,以便仅选择匹配的ID。它有一点参与选择,但它也提供了一个简洁的功能,比如说你过滤10个属性,并返回所有那些有10个匹配的。很酷,但说没有一个匹配100%。你可以说嘿,我发现没有匹配,但这些有9个10或90%匹配。 (只要确定,如果我搜索一个蓝眼睛的金发女性,我没有得到消息说没有找到,但这里是下一个最接近匹配的包含蓝眼睛的金发女郎,匹配得分为60%。那就是非常不酷)
如果您选择拆分表格,还有更多需要考虑的事项,例如如何将属性作为数字,日期和文本存储在一个列中?或者是这些单独的表或列。无论是宽表还是分表,都不容易回答。