假想项目
项目名:***平台
项目规模:100万数据量
数据特征:每条信息有标题、作者、发布时间、唯一的识别码、正文
其中标题识别码是英文与数字的组合,正文假设500汉字。
一般项目的搜索功能
一般项目,这里特指数据量规模在1万以下的规模,简单的企业站、社区系统、博客系统,数据量不大,搜索功能直接用like查询就能满足使用需求,一般配置的服务器2核4G就能发挥很好的性能了。
百万级以上规模项目的搜索功能
但是项目规模达到百万级以上时,就不能用简单的like查询就行搜索了。like查询需要对数据表进行遍历,需要把表的内容加载至内存,这里简单计算下内存开销:
100万条数据,每条信息500字正文
每个汉字是2个字节,1024字节=1Kb,1024Kb=1Mb,1024Mb=1G
100万条数据全匹配产生的数据量大小是:1000000*500*2/1024/1024/1024≈1G,这里不考虑分页,1G数据的传输就会消消耗大量的带宽资源,更不好说CPU和内存消耗了
因此,百万级以上规模的搜索功能,必须要使用sphinx这类专门的全文索引工具
Like查询时,MySQL内部都做了什么
Like查询没有用到索引,需要对全表进行扫描,将所查到的每一行符合条件的数据放到结果集里面,然后返给客户端。
服务端并不需要保存一个完整的结果集,取数据和发数据流程如下:
- 获取一行,写到net_buffer中,它的内存的大小由参数net_buffer_length确定,默认16k;
- 重复获取行,直到net_buffer写满,调用网络接口发出去;
- 如果发送成功,清空net_buffer,然后继续取下一行,重复1、2过程;
- 如果发送函数返回EAGAIN 或者 WSAEWOULDBLOCK,此时表示“本地网络栈”(socket send buffer)写满了,进入等待(为什么会写满,因为没发出去)。直到网络栈重新可写,再继续发送。
由取、发数据流程可知:
- 一个查询在发送过程中,占用MySQL的内部内存最大就是net_buffer_length,它是有上限控制的,并不会肆意占用内存;
- socket send buffer (默认定义/proc/sys/net/core/wmem_default)也是有上限控制的,如果它被写满,就会暂停读数据的流程。
like查询有这以上2个瓶颈限制,导致查询速度缓慢,全表扫描会占用大量的CPU性能,匹配到的结果发送的过程中,又受到net_buffer和send_buffer的双重限制,这决定了like查询不适合处理10万以上数据量的表
实战经验分享
我们已有多个大数据量规模项目的实战经验,我们开发了一款专业的高性能开发框架,云豹框架,感兴趣的可以百度搜索了解下。