设计一个在线约会网站,用户信息表:国家,地区,城市,性别,眼睛颜色等等。支持各种组合来搜索用户:最后在线时间,评分等进行排序的限制。
索引来排序,还是先检索数据再排序?
索引排序:严格限制索引和查询的设计。索引做评分排序,则WHERE 条件中的 age BETWEEN 18 AND 25 就无法使用索引。
1、支持多种过滤条件
(1)(country,sex)作为前缀:country、sex选择性很低,很多查询用到
和不应该在选择性低的列上创建索引是矛盾,因为:
a、sex使用的太频繁。
b、加了这列没坏处,即没用sex,增加and sex in ('m','f'),不会过滤任何行,能够匹配索引最左前缀,但不要让in()列表太长。
(2)优化索引和优化查询要平衡:(sex,country,age),(sex,country,region,age),(sex,country,region,city,age),重用索引,in()技巧很重要
WHERE eye_color in('brown','blue','hazel')
AND hair_colr in ('black','red','blonde','borwn')
AND sex in ('f','m')
优化器会转成3*4*2=24种组合,查询优化很多时间,并消耗大量的内存
(3)范围查询较多的列放在后面:例age列
2、避免多个范围查询
explain的输出很难区分范围查询(<,>,between)和列表值查询in(),因为explain中的type都是range,访问效率不同,前者索引不能用了,后者却可以。
last_online列,查询显示在过去几周上线过的用户:
WHERE eye_color in('brown','blue','hazel')
AND hair_colr in ('black','red','blonde','borwn')
AND sex in ('f','m')
AND last_online > DATE_SUB(NOW(),INTERVAL 7 DAY)
AND age between 18 and 25
last_onlin、age列索引,无法同时使用
解决办法:active列,每次登陆设为1,连续7天未登陆设为0
3、优化排序
SELECCT <cols> FROM profiles WHERE sex='M' ORDER BY rating limit 10; //同时使用order by 和limit ,如果没有索引的话,会很慢
SELECCT <cols> FROM profiles WHERE sex='M' ORDER BY rating limit 100000,10;//即使有索引,翻页到比较靠后时,查询也慢。
解决办法:(1)限制用户能够翻页的数量,实际上这对用户的体验不大,因为用户很少真正在乎搜索过的低10000页。
(2)延迟关联,通过使用腹杆索引查询返回需要的主键,在根据这些主键关联原表格所需要的行。这可以减少MySQL扫描那些需要丢弃的行数。下面这个查询显示了如何高效的使用(sex,rating)索引进行排序和分页
SELECT <cols> FROM profiles INNER JOIN (
SELECT <primary key cols> FROM profiles
WHERE x.sex = 'M' ORDER BY rating 10000,10
) AS X using (<primary key cols>);
表里有100万记录,如图:



20W的数据:
