2011-01-06 74 views
1

我有了很多列的用戶表,它看起來大致是這樣的:建議需要適當的索引中搜索與許多字段的表上

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語句。因此,如果有人選擇抽菸:不和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

請告訴我,你的'真正'查詢中使用綁定變量。 – Gerrat 2011-01-06 01:26:13

+0

任何特殊原因:height,looking_for_age1,looking_for_age2,country_id都是有符號整數(4字節)。有人可以是-2147483648英尺高或2147483647歲?你不認爲tinyint UNSIGNED會適合年齡和country_id(0..255歲,0..255個國家)身高可能應該是小數(3,2)。你有沒有考慮過當你在表中有兩百萬行時會發生什麼,你需要擴展現有的枚舉? – 2011-01-06 01:27:23

+0

@Gerrat,我還沒有使用綁定變量,你能建議一個很好的閱讀? – BugBusterX 2011-01-06 01:51:47

回答

0

我有一個表在工作與相同的東西,很多列和1000種不同的方式來選擇。這是一場噩夢。然而,我確實發現,經常使用某些過濾器組合。那些我會創建索引並留下其他很少用於緩慢運行的索引。在MSSQL中,我可以運行一個查詢來顯示已經針對數據庫運行的最昂貴的查詢,mySQL應該有類似的事情。一旦我擁有了它們,我就創建一個涵蓋列的索引來加速它們。最終,你將擁有90%的覆蓋率。除非我有AK47指向我,否則我個人絕不會再設計這樣的桌子。 (如果您需要添加一堆或多條記錄,我的索引比表中的數據大3倍,這非常不酷)。 雖然我不知道該如何重新設計表格,但我的第一個想法是將表格拆分爲兩個,但這會增加其他地方的頭痛。

用戶表(用戶ID,姓名)

1, Lisa 
2, Jane 
3, John 

用戶屬性表(用戶ID,爲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%。非常不爽)

如果您選擇拆分表,還有更多的事情需要考慮,比如如何將屬性保存爲數字,日期和文本到單個列中?或者是這些單獨的表格或列。寬表或分表不容易回答。

+0

「藍眼睛的金髮男孩」會激怒很多用戶,並讓其他人質疑他們的性行爲LOL!這是一個有趣的方法,但我不知道這是否會更快。 – BugBusterX 2011-01-10 12:47:35

+0

速度明智我不能真正告訴沒有測試它,但我認爲這將是一個慢點擊比目前表的索引,完全覆蓋您的查詢。不同之處在於,與沒有覆蓋索引的桌面打擊相比,它不會更慢。也許,除了當前的表格之外,您還可以添加拆分表格,並僅將其用於這類變量搜索。你不需要從你的用戶表中索引垃圾,但是你需要保持兩個表的同步,這不是一個大問題。不知道,它取決於你。這是值得的麻煩。 – 2011-01-10 13:14:22

0

每個可搜索字段都需要它自己的單列索引。如果您的表格很大,並且您沒有搜索條件的索引,則每行都必須進行掃描。

添加一個新用戶會更慢,但是描述你的情況的方式我想你的查詢主要是通過幾個插入選擇。