Learning MySQL Notes I 八月 26th, 2010

Summary

 

列函数:

count()

min(),max(),sum(),avg(),

distinct

聚集查询:

group by column1,column2... having ...

 

Sequence


 

AUTO_INCREMENT:

  • 生成连续正整数(unsigned int,tinyint...),通常从1开始,不能为NULL;
  • 索引上的要求,primary key 或者 unique; 
  • 删除顶端数值后,BDB从当前最大值+1开始,MyISAM或者InnoDB则是过去没有使用的最小整数;

 

id int unsigned not null auto_increment primary key,

OR

id int unsigned not null auto_increment unique,

 

查询序列值:

针对每一个mysql连接

 

select last_insert_id();

 

根据顶端值使用:

 

alter table tbl_name auto_increment = 1;

 

 

多列序列 :

  • 把auto_increment列和某列链接在一起,使其构成一个索引,且auto列需放在最后;
  • primary key不能包含NULL值;

 

id   int unsigned not null auto_increment,

name varchar(20) not null,

primary key(name,id)

 

计数器:

last_insert_id(expr)句法;

 

insert into tbl_name (key1,key2) values('xxx',last_insert_id(1))

on duplicate key update key2 = last_insert_id(key2+2);


select last_insert_id(); //返回此更新后的key2值

 

循环序列

Join
inner join:
  • 表间相同行信息匹配;
  • 连接列需要索引;
select * from tbl_name1,tbl_name2 where tb1_name1.column1 = tb2_name.column2;
等价于
select * from tbl_name1 inner join tbl_name2 on tb1_name1.column1 = tb2_name.column2;
其中若tb1_name1.column1和tb2_name.column2相同,那么可以简写
select * from tbl_name1 inner join tbl_name2 using column1;

where 一般的用于限定连接行,而on和using用于连接表
left join/right join:
表外连接,寻找不匹配左表的条件的值,默认NULL补全;
select * from tbl_name1 left join tbl_name2 on tb1_name1.column1 = tb2_name.column2
where tbl_name2.column2 IS NULL;
self join:
select * from tbl_name as tb1 left join tbl_name as tb2 on tb1.column = tb2.column;
统计连续行的差值:
select tb1.id as seq1,tb2.id as seq2,
tb2.column - tb1.column
from tbl_name as tb1 left join tbl_name as tb2 
on tb1.column+1 = tb2.column;
统计连续行的总和:
select tb1.id as seq1,tb2.id as seq2,
sum(tb2.column)
from tbl_name as tb1 left join tbl_name as tb2 
on tb1.column >= tb2.column
group by tb1.id;
Statistical
统计函数:
STDDEV_SAMP() N-1自由度的抽样标准差;
VAR_SAMP() N-1自由度的抽样方差;
STDDEV() 总体标准差;
VARIANCE() 总体方差;
线性回归:
y = bx+a;
select 
@n := count(id),
@sumxy := sum(x*y),//xy的和
@sumxx := sum(x*x),//x的平方和
@sumx := sum(x),//x的和
@sumy := sum(y), //y的和
@meany := avg(y),//y的平均数
@meanx := avg(x)
from tbl_name \G;

select 
@b := (@n*@sumxy - @sumx*@sumy)/(@n*@sumxx - @sumx*@sumx);

select
@a := (@meany - @b*@meanx);
关系系数:
select 
@n := count(id),
@sumxy := sum(x*y),//xy的和
@sumxx := sum(x*x),//x的平方和
@sumx := sum(x),//x的和
@sumy := sum(y), //y的和
@meany := avg(y),//y的平均数
@meanx := avg(x)
from tbl_name \G;

select 
(@n*@sumxy - @sumx*@sumy)/sqrt((@n*@sumxx - @sumx*@sumx)*(@n*@sumyy - @sumy*@sumy));
随机数:
order by rand();
rand(x);
洗牌算法:
import itertools,random
face = ['A','B','C','D']
sult = [str(i) for i in range(1,13)]


def shuff():
    card = map(lambda x:(x[0]+x[1],random.random()),itertools.product(face,sult))
    return map(lambda x:x[0],sorted(card,key = lambda x:x[1]))

>>> shuff()
['C8', 'D6', 'A11', 'B10', 'B3', 'D9', 'C4', 'A4', 'A1', 'C9', 'B2', 'B5', 'D8', 'B12', 'B1', 'D5',
 'B6', 'C11', 'A3', 'C3', 'D7', 'A7', 'C7', 'B7', 'A6', 'A5', 'C5', 'D11', 'A10', 'D4', 'A12', 'A2',
 'C2', 'D12', 'A9', 'B4', 'C6', 'D3', 'D2', 'D1', 'B9', 'C1', 'D10', 'B8', 'C12', 'A8', 'C10', 'B11']
>>> shuff()
['D1', 'A6', 'C2', 'B8', 'B6', 'D2', 'D10', 'A2', 'A9', 'B2', 'D3', 'C1', 'C4', 'B12', 'B9', 'A10',
 'D8', 'C3', 'D9', 'C8', 'C5', 'A3', 'A5', 'B5', 'B3', 'D7', 'C12', 'A1', 'B11', 'B4', 'A11', 'C7', 
'D11', 'D4', 'B1', 'C9', 'A7', 'B10', 'D12', 'D5', 'C6', 'A4', 'B7', 'A12', 'D6', 'C11', 'C10', 'A8']
Duplicates
防止重复:
unique,primary key
重复项写入:
insert ignore into ... ;//判定是否存在一个拷贝
replace into ...;//非键列需要被替换
insert ... on duplicate update ... ;//需要写入,索引列发生重复
访问日志统计
Tags: Database

Posted in Notes | Comments(1)»

在线即时通讯服务,就是通常所说的WEBIM.当前在Facebook等SNS中比较常见.本文主要探讨当前产品中WEBIM用户聊天消息的存取方案.

首先,我们看看WEBIM产生的消息特征:

  • 频繁发生
  • 时序上下文关联
  • 多维标识
  • 有限长度文本

除此以外,我们的WEBIM产品还具有"多写少读"和"短写长读"的特点,因此这里把读和写分开设计.

"巧妇难为无米之炊"首先来看看,消息是怎么写入的.按照I/O流从前往后依次涉及:

  • Chat Server 这个嘛,自然就是接入系统的聊天服务器了
  • Message Unit 部署在Chat Server端的 系统客户端 (这个句子貌似有点怪 -_-#)
  • Message Stream Server流式消息服务
  • Context Intergradation Cache 上下文聚合缓存
  • Persistence Layer 持久化存储

好吧,上图

  • Message Unit 被设计成采用UDP 协议的异步通讯客户端.消息文本可以被编译成二进制格式, 已节省传输带宽, 参考Google Protocol Buffer.
  • Message Stream Server 将包含一个Stream UDP Server. 其采用流式服务器设计, 可以高速的将消息交给后续流程, 而不被阻塞; 另一个重要的部分是Dispatch 服务器, 它将流服务器传递的消息传输至上下文聚集堆.
  • Context Intergradation Cache 接受Dispatch 传递的消息(如果为二进制格式,此处还原为文本), 根据其中的上下文流水号, 压入相应的会话消息缓存栈栈顶; 伴随着预定义的栈生命周期结束或者显式的会话结束信号,将整个会话栈的内容(context) 传输至持久化层.
  • Persistence Layer 接收前述context, 并根据context 的内容和属性, 构建查询索引(会话流水, 发起人, 接受人...)随后完成context 实体存储.由于大量context 的频繁写硬盘, 可以预见磁盘IOPS 将成为瓶颈. 针对context 的结构类型不同看法, 该层可以通过以下几种方式实现:
  1. 关系数据库:context 在粗粒度上具有结构化特征. 因此可以采用MySQL Archive 引擎, 相对于MyISAM 等引擎, 其大幅减少物理存储开销, 也提供了高效的读写效率, 并满足''Read Consistency''.
  2. 文档数据库: 采用JSON,XML 或者YAML 组织文档类型的半结构化数据库. 参考BaseX,MongoDB.
  3. 分布式文件系统

 

既然文本已经写入,那我们就来关注下如何读出这些聊天记录.这里需要交代的是,我们WEBIM的产品需求是允许用户查阅历史聊天记录,但并不允许用户删除这写记录,恩,给了我的就别想拿走:)

按照读出的I/O流,基本上涉及:

  • Context Cache,主要包括持久化层Index的Cache 和 具体记录的Cache.
  • Persistence Storage,就是前文所述的持久化层

上图,上图,我是图片控

 

当浏览器请求具体的历史消息数据时, 逻辑层会首先在Context Index Cache 中寻找. 命中即返回Context Cache 中相应的数据; 反之, 在持久化存储中查找, 并更新内容缓存和索引缓存.

根据实际业务,Context Cache 的更新策略需要满足Results Consistency.

 

 

有些地方"不能说太细",敬请谅解.好了,就到这里,休息休息~~

当搜索引擎引导我们访问一个目标站点的时候,有些时候我们会看到,当前站点会提供一个包含高亮搜索关键词的浮层.这个浮层显示了站内其他含有这个关键词的文章信息.方便的聚合了信息的同时,也延长了用户在网站的停留时间.

根据这个思路,我设计了一种面向搜索引擎的服务(SeoS),旨在提升搜索引擎优化效果,并提供一种效果检测的数据方法.

图中字母含义:

  • S  百度 谷歌等搜索引擎们
  • U  伟大的客户端
  • W  吐页面的站点服务器
  • Sv           SeoS服务
  • KeyDB     搜索关键字存储
  • IndexDB  站内全文索引
  • KeyFS      以关键词为核心的列表页面

按照数字顺序和箭头指向表明了一个基本的访问服务流程.这里简要说明一下:

Q:站点如何得到搜索引擎关键词呢?

A:可以参考HTTP REFER信息

前端服务器将关键词(以下简写KW)传给SeoS服务,Seos通过查询和KW相关的全文索引或者标签索引.返回前端服务器相关的信息列表结果;并异步地将该关键词持久化保存.

那么用户在页面看到的就不仅仅是正文本身,还可以得到为本次浏览而定制的推荐列表.

再来看看记录了关键词信息的KeyDB,通过记录,我们可以准确的知道站点在搜索引擎关键字命中的情况;更重要的是,针对这些关键字,我们可以生成相应的聚合列表页.从而提升站点在该KW上的权重,人为的创造"犹大效应":)

在此基础之上,通过合理的构建KeyDB,我们完全可以建立起搜索引擎爬虫的访问行为规律,动态改变网站的关键词和整体更新频率,保障网站的人气和内容价值.也对搜索引擎更加友好.

Tags: 架构 产品

Posted in 产品 | Comments(3)»

在实际生产中,一套分布式的程序可能需要被部署在很多环境相同的服务器上.

如何实现程序的自动部署不仅可以降低因版本冲突而导致的服务异常,也可以未将来的持续集成做基础准备.

这里采用的代码版本控制程序为Subversion,由中央版本库向多台服务器同步代码的方法有很多,基本上都是通过使用hook(post-commit)来实现的.

这里记录下我的post-commit:

 

use Net::SSH::Expect;


#此处添本代码仓库需要同步的服务器组
my @cluster = ('192.168.1.191',
               '192.168.1.190',
               '192.168.1.193'
              );


foreach $svr (@cluster) {
   my $ssh = Net::SSH::Expect->new(
   host =$svr,
   password ='xxx', 
   user ='xxx',
   raw_pty =1
   );
   my $logins = $ssh->login();
   my $command = $ssh->exec('svn up /path');
   $ssh->close();
}
Tags: Perl

Posted in 生产力 | Comments(0)»

Django HTTP Module Sheet 七月 27th, 2010

好吧,放一张django的http架构图出来

Tags: Django

Posted in Notes | Comments(0)»

Web服务日志分析[上] 七月 27th, 2010

 

对于一个程序来说,Loging是一件非常有利的武器,其可以帮助程序员快速的找到BUG,分析性能瓶颈等等...甚至还可以在技术社区彰显一番代码的华 丽,实乃死coder居家旅行必备之宝.而网站访问日志除了对开发者有修改缺陷,提升功力之良效以外,对待运营人员,也是分析用户行为的第一手宝贵资料.

本博这里打算通过若干系列文章来讲讲如何有效运用访问日志来改善程序和用户行为分析:)
问: 为啥不用第三方工具?
答: 什么AWState之类的最讨厌了,速度慢不说,扩展也好复杂滴 -_-b 再说,咱这个应用上千万的请求,日志都大到不行,排个序都得小半天.玩死了服务器 那就罪过了

我们还是站在程序员的角度来审视程序的运行状态;通过数字手段来分析用户访问状况

既然一切都从访问日志开始,那么首先就来parser weblog吧.让数据变得更加可读些,嘿嘿,自然也更方便处理些.

这里的日志格式如下:
124.205.30.210 - - [14/Dec/2009:16:02:46 +0800] "GET /HLRelationLog/ent.hunantv.com/y/l/20090306/225172.html HTTP/1.1" 404 252
124.205.30.210 - - [14/Dec/2009:16:04:51 +0800] "GET /HLRelationLog/ent.hunantv.com/y/l/20090901/410652.html HTTP/1.1" 404 252
211.152.32.122 - - [14/Dec/2009:16:15:10 +0800] "GET /manager/html HTTP/1.1" 404 210
124.205.30.210 - - [14/Dec/2009:17:02:18 +0800] "GET / HTTP/1.1" 200 44
124.205.30.210 - - [14/Dec/2009:17:02:19 +0800] "GET /favicon.ico HTTP/1.1" 404 209
124.205.30.210 - - [14/Dec/2009:17:24:59 +0800] "GET /HLRelationLog/ent.hunantv.com/x/20090616/331092.html"

格式很简单:来路IP,本地时间,以及访问的路径.实际情况下往往还有一个User-Agent.但是在本篇我们无视这个参数.先将这些数据"取"出来存 入数据库再说.

awk -F ' ' '/HLRelationLog/ {printf("insert into logs (url,ip,time) values (\"%s\",\"%s\",\"%s\");",$7,$1,substr($4,2))}' access.log > target.sql
然后将数据导入
mysql -u root -p -h 8.8.8.8 < target.sql

这里简单再来看看大致的访问情况:

awk -F ' ' '/HLRelationLog/ {print $7}' access.log |sort|uniq -c|sort -nr > sort.txt

结果摘抄如下:

 

13102 /HLRelationLog/ent.hunantv.com/e/h/20080917/49514.html
   7112 /HLRelationLog/ent.hunantv.com/e/h/20080719/23308.html
   6539 /HLRelationLog/ent.hunantv.com/m/20091231/536520.html
   6451 /HLRelationLog/ent.hunantv.com/m/20090427/281233.html
   5739 /HLRelationLog/ent.hunantv.com/m/20091222/527487.html
   5248 /HLRelationLog/ent.hunantv.com/x/20091224/529517.html
   4863 /HLRelationLog/ent.hunantv.com/y/20091219/524512.html
   4597 /HLRelationLog/ent.hunantv.com/m/20091221/526802.html
   4168 /HLRelationLog/ent.hunantv.com/m/20091221/526782.html
   4162 /HLRelationLog/ent.hunantv.com/y/20081028/87956.html
   3951 /HLRelationLog/ent.hunantv.com/m/20091222/527342.html
   3729 /HLRelationLog/ent.hunantv.com/e/20080716/22250.html
   3631 /HLRelationLog/ent.hunantv.com/e/h/20080728/26581.html
   3561 /HLRelationLog/ent.hunantv.com/m/20091222/527785.html
   3372 /HLRelationLog/ent.hunantv.com/e/h/20080903/42076.html
   3339 /HLRelationLog/ent.hunantv.com/y/20091216/522056.html
   3163 /HLRelationLog/ent.hunantv.com/y/l/20091221/525879.html
   2998 /HLRelationLog/ent.hunantv.com/y/20091216/521082.html
   2914 /HLRelationLog/ent.hunantv.com/x/20091221/526583.html
   2889 /HLRelationLog/ent.hunantv.com/y/20081231/154998.html
   2851 /HLRelationLog/ent.hunantv.com/z/20091225/530766.html

下面来处理下频道的访问分布,每个link的倒数第三段[x,y,e...]:首先通过awk得到每个link的频道的识别符和访问数量,丢进一个文件

map(lambda x:[x,sum(map(lambda y:int(y[1]),filter(lambda z:z[0]==x,t)))],set(map(lambda x:x[0],t)))
>>>
[['x\n', 48173], ['y\n', 266146], ['d\n', 4035], ['z\n', 40631], ['e\n', 98009], ['ent\n', 558], ['m\n', 174542], ['t\n', 59660]]

来看看并发的情况: 

 

tail -10000 access.log | awk '{print $4;}' | sort | uniq -c | sort -nr | head

=====我是分割线====

33 [31/Dec/2009:22:03:18
     16 [25/Dec/2009:18:16:07
     14 [25/Dec/2009:18:16:06
      9 [31/Dec/2009:22:03:19
      8 [25/Dec/2009:18:13:35
      7 [31/Dec/2009:22:06:38
      7 [31/Dec/2009:19:22:40
      7 [25/Dec/2009:19:55:54
      7 [25/Dec/2009:14:39:06
      7 [02/Jan/2010:18:37:54