正确索引具有要搜索的许多字段的表所需的建议

时间:2011-01-06 01:17:08

标签: mysql sql indexing

我有一个包含许多列的用户表,它看起来大致如下:

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;

因为用户可以选择要过滤的任何字段组合,所以我不确定如何对此表进行索引,我是否应该在所有可以过滤的字段上创建单个列索引?你会提出什么建议?

2 个答案:

答案 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%。那就是非常不酷)

如果您选择拆分表格,还有更多需要考虑的事项,例如如何将属性作为数字,日期和文本存储在一个列中?或者是这些单独的表或列。无论是宽表还是分表,都不容易回答。