REPLACE INTO 为什么返回"2 rows affected"

表的结构:

desc urls;
+——-+———————+——+—–+———+——-+
| Field | Type | Null | Key | Default | Extra |
+——-+———————+——+—–+———+——-+
| id | bigint(16) unsigned | NO | PRI | NULL | |
| url | varchar(255) | NO | | NULL | |
| md516 | varchar(32) | NO | UNI | | |
+——-+———————+——+—–+———+——-+
3 rows in set (0.01 sec)


原有数据:

+—-+———————–+——————+
| id | url | md516 |
+—-+———————–+——————+
| 0 | http://www.162cm.com/ | 49f6f2aaa26c124a |
+—-+———————–+——————+
1 row in set (0.00 sec)

执行的语句:

REPLACE INTO urls (`url`,`md516`,`id`) VALUES (‘http://www.162cm.com/’,’49f6f2aaa26c124a’,0);

而执行这条语句的返回是:

Query OK, 2 rows affected (0.00 sec)

为啥呢….看起来数据啥也没变,不是吗?
看文档:http://au2.php.net/mysql_affected_rows:

Returns the number of affected rows on success, and -1 if the last query failed.

If the last query was a DELETE query with no WHERE clause, all of the records will have been deleted from the table but this function will return zero with MySQL versions prior to 4.1.2.

When using UPDATE, MySQL will not update columns where the new value is the same as the old value. This creates the possibility that mysql_affected_rows() may not actually equal the number of rows matched, only the number of rows that were literally affected by the query.

The REPLACE statement first deletes the record with the same primary key and then inserts the new record. This function returns the number of deleted records plus the number of inserted records.

我的vimrc 文件

嗯,给大家共享一下。都是从各地copy来的。

“vimim 相关
let g:vimim_enable_static_enu=1
“let g:vimim_enable_sexy_input_style=1
” 关闭中文标点
let g:vimim_disable_chinese_punctuation=1
“中英文之间不加空格
let g:vimim_disable_seamless_english_input=1

set dictionary-=/etc/funclist.txt dictionary+=/etc/funclist.txt
“Use the dictionary completion
set complete-=k complete+=k

“自动补全..
set completeopt=longest,menu

imap
set nu
autocmd FileType python set complete+=k~/.vim/tools/pydiction

filetype plugin indent on
set nocp
filetype plugin on
set helplang=cn
map :Project
“autocmd BufNewFile *.py 0r ~/.vim/template/simple.py


set ignorecase
set shiftwidth=4
set softtabstop=4
set tabstop=4

set nocompatible ” Use Vim defaults (much better!)
“set ai ” always set autoindenting on
“set backup ” keep a backup file
set viminfo=’200,f1,<1500 " read/write a .viminfo file, don't store more " than 50 lines of registers set history=1500 " keep 50 lines of command line history set ruler " show the cursor position all the time if has("autocmd") filetype plugin indent on autocmd FileType python set omnifunc=pythoncomplete#Complete autocmd FileType ruby set omnifunc=rubycomplete#Complete autocmd FileType c set omnifunc=ccomplete#Complete autocmd FileType ada set omnifunc=adacomplete#Complete autocmd FileType php set omnifunc=phpcomplete#CompletePHP autocmd FileType javascript set omnifunc=javascriptcomplete#CompleteJS autocmd FileType html set omnifunc=htmlcomplete#CompleteTags autocmd FileType css set omnifunc=csscomplete#CompleteCSS autocmd FileType xml set omnifunc=xmlcomplete#CompleteTags autocmd FileType sql set omnifunc=sqlcomplete#Complete endif set ru "该命令打开 VIM 的状态栏标尺。 默认情况下, VIM 的状态栏标尺在屏幕底部, 它能即时显示当前光标所在位置在文件中的行号、列号, 以及对应的整个文件的百分比。 打开标尺可以给文件的编辑工作带来一定方便。 set nocp "该命令指定让 VIM 工作在不兼容模式下。 在 VIM 之前, 出现过一个非常流行的编辑器叫 vi。 VIM 许多操作与 vi 很相似,但也有许多操作与 vi 是不一样的。 如果使用“:set cp”命令打开了兼容模式开关的话, VIM 将尽可能地模仿 vi 的操作模式。 "也许有许多人喜欢“最正统的 vi”的操作模式, 对于初学者来说, vi 里许多操作是比较不方便的。 "举一个例子, VIM 里允许在 Insert 模式下使用方向键移动光标, 而 vi 里在 Insert 模式下是不能移动光标的, 必须使用 ESC 退回到 Normal 模式下才行。 "再举一个例子, vi 里使用 u 命令可以撤消一次先前的操作, 再次按下 u 时, 将撤消“撤消”这个动作本身,也就是我们常说的“重复”(redo)。 而 VIM 里可以使用 u 命令撤消多步操作, “重复”使用的快捷键是 Ctrl + R。 "使用兼容模式后, VIM 将放弃这些新的功能, 尽量模仿 vi 的各种操作方式。 只有在不兼容模式下, 才能更好地发挥 VIM 自身的特点。 Bram 爷爷强烈推荐大家使用 VIM 的不兼容模式, 滇狐也是这样推荐的。 请务必在你的 .vimrc 中的第一行写上: “set nocp”。 set hls "搜索时高亮显示被找到的文本。 该指令的功能在 vimtutor 中已经有过介绍, 这里就不多说了。 其实似乎许多人并不喜欢这个功能。 "set is "搜索时在未完全输入完毕要检索的文本时就开始检索。 vimtutor 对该命令也有过介绍, 滇狐并不喜欢这个功能, 因此滇狐自己的配置文件里是没有这条命令的。 但是周围有朋友很喜欢这个, 因此滇狐还是将它列在这里。 syntax on "打开关键字上色。 进行程序设计的朋友应该都知道关键字上色是什么东西, 因此这里就不多说了。 不进行程序设计的朋友不妨也打开这个功能, 虽然不一定能够用得着, 但这个功能其实也是很好玩的。 set backspace=indent,eol,start "设想这样一个情况: 当前光标前面有若干字母, 我们按下 i 键进入了 Insert 模式, 然后输入了 3 个字母, 再按 5 下删除(Backspace)。 默认情况下, VIM 仅能删除我们新输入的 3 个字母, 然后喇叭“嘟嘟”响两声。 如果我们“set backspace=start”, 则可以在删除了新输入的 3 个字母之后, 继续向前删除原有的两个字符。 "再设想一个情况: 有若干行文字, 我们把光标移到中间某一行的行首, 按 i 键进入 Insert 模式, 然后按一下 Backspace。默认情况下, 喇叭会“嘟”一声, 然后没有任何动静。 如果我们“set backspace=eol”, 则可以删除前一行行末的回车,也就是说将两行拼接起来。 "当我们设置了自动缩进后, 如果前一行缩进了一定距离, 按下回车后, 下一行也会保持相同的缩进。 默认情况下, 我们不能在 Insert 模式下直接按 Backspace 删除行首的缩进。 如果我们“set backspace=indent”, 则可以开启这一项功能。 "上述三项功能, 你可以根据自己的需要, 选择其中一种或几种, 用逗号分隔各个选项。 建议把这三个选项都选上。 set whichwrap=b,s,<,>,[,]
“默认情况下, 在 VIM 中当光标移到一行最左边的时候, 我们继续按左键, 光标不能回到上一行的最右边。 同样地, 光标到了一行最右边的时候,我们不能通过继续按右跳到下一行的最左边。 但是, 通过设置 whichwrap 我们可以对一部分按键开启这项功能。如果想对某一个或几个按键开启到头后自动折向下一行的功能, 可以把需要开启的键的代号写到 whichwrap 的参数列表中,各个键之间使用逗号分隔。 以下是 whichwrap 支持的按键名称列表:

” * b
” 在 Normal 或 Visual 模式下按删除(Backspace)键。
” * s
” 在 Normal 或 Visual 模式下按空格键。
” * h
” 在 Normal 或 Visual 模式下按 h 键。
” * l
” 在 Normal 或 Visual 模式下按 l 键。
” * < " 在 Normal 或 Visual 模式下按左方向键。 " * >
” 在 Normal 或 Visual 模式下按右方向键。
” * ~
” 在 Normal 模式下按 ~ 键(翻转当前字母大小写)。
” * [
” 在 Insert 或 Replace 模式下按左方向键。
” * ]
” 在 Insert 或 Replace 模式下按右方向键。
set encoding=utf-8
“设置当前字符编码为 UTF-8。 UTF-8 是支持字符集最多的编码之一, 在 UTF-8 下进行工作, 会带来许多方便之处。 由于 VIM 在运行过程中切换 encoding 会造成许多问题, 如提示信息乱码、 register 丢失等, 因此强烈建议大家在启动 VIM 的时候把 encoding 设置为 UTF-8, 在编辑非 UTF-8 的文件时, 通过 fileencoding 来进行转码。
set langmenu=zh_CN.UTF-8
“使用中文菜单, 并使用 UTF-8 编码。 如果没有这句的话, 在非 UTF-8 的系统, 如 Windows 下, 用了 UTF-8 的 encoding 后菜单会乱码。
“language message en_US.UTF-8
“使用中文提示信息, 并使用 UTF-8 编码。 如果没有这句的话, 在非 UTF-8 的系统, 如 Windows 下, 用了 UTF-8 的 encoding 后系统提示会乱码。
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
“设置编码的自动识别。 关于这条设置的详细含义, 请参看这篇文章。
“set ambiwidth=double
“防止特殊符号无法正常显示。 在 Unicode 中, 许多来自不同语言的字符, 如果字型足够近似的话, 会把它们放在同一个编码中。但在不同编码中, 字符的宽度是不一样的。 例如中文汉语拼音中的 ā 就很宽, 而欧洲语言中同样的字符就很窄。 当 VIM 工作在 Unicode 状态时, 遇到这些宽度不明的字符时, 默认使用窄字符, 这会导致中文的破折号“——”非常短, 五角星“★”等符号只能显示一半。因此, 我们需要设置 ambiwidth=double 来解决这个问题。
filetype plugin indent on
“开启文件类型自动识别, 启用文件类型插件, 启用针对文件类型的自动缩进
set smarttab
“当使用 et 将 Tab 替换为空格之后, 按下一个 Tab 键就能插入 4 个空格,
“但要想删除这 4 个空格, 就得按 4 下 Backspace, 很不方便。 设置 smarttab
“之后, 就可以只按一下 Backspace 就删除 4 个空格了。
“set spell
“打开拼写检查。 拼写有错的单词下方会有红色波浪线, 将光标放在单词上, 按 z= 就会出现拼写建议, 按 ]s 可以直接跳到下一个拼写错误处。

“set tw=78
“设置光标超过 78 列的时候折行。
set lbr
“不在单词中间断行。 设置了这个选项后, 如果一行文字非常长, 无法在一行内显示完的话, 它会在单词与单词间的空白处断开, 尽量不会把一个单词分成两截放在两个不同的行里。
set fo+=mB
“打开断行模块对亚洲语言支持。 m 表示允许在两个汉字之间断行, 即使汉字之间没有出现空格。 B 表示将两行合并为一行的时候, 汉字与汉字之间不要补空格。 该命令支持的更多的选项请参看用户手册。


” c/c++
set sm
“显示括号配对情况。 打开这个选项后, 当输入后括号 (包括小括号、中括号、大括号)
“的时候, 光标会跳回前括号片刻, 然后跳回来, 以此显示括号的配对情况。
set ai
“打开普通文件类型的自动缩进。 该自动缩进不如 cindent 智能, 但它可以为你编辑非
“C/C++ 文件提供一定帮助。
set selectmode=
“不使用 selectmode。

set keymodel=
“不使用“Shift + 方向键”选择文本, “Shift + 方向键”代表向指定方向跳一个单词。 如果你喜欢这项功能的话, 可以使用“set keymodel=startsel,stopsel”打开它。
set keymodel=startsel,stopsel

set wildmenu
“在命令模式下使用 Tab 自动补全的时候,
“将补全内容使用一个漂亮的单行菜单形式显示出来。
set sw=4
“自动缩进的时候, 缩进尺寸为 4 个空格。
set ts=4
“Tab 宽度为 4 个字符。
set et
“编辑时将所有 Tab 替换为空格。
“该选项只在编辑时将 Tab 替换为空格, 如果打开一个已经存在的文件, 并不会将已有的 Tab 替换为空格。 如果希望进行这样的替换的话, 可以使用这条命令“:retab”。
retab
“set paste
“set nopaste
set pastetoggle=
“很多兄弟都碰到过这样一个问题,在vim中粘贴代码有时会自动增加缩进,造成代码排版
“的混乱。如何让它不缩进,保持原格式?其实vim有一个paste开关。
“输入 :set paste
“需要关闭时
“输入:set nopaste
“我是在vimrc中加入了:
“set pastetoggle=
“这样就可以用F3来切换了。
if (has(“win32”))

“————————————————————————-
” Win32
“————————————————————————-
if (has(“gui_running”))
set guifont=Bitstream_Vera_Sans_Mono:h9:cANSI
set guifontwide=NSimSun:h9:cGB2312
endif

else
if (has(“gui_running”))
set guifont=Bitstream Vera Sans Mono 9
endif
endif

“如果去掉这一行,默认值set mouse=a就生效了,这时不能用鼠标选中复制.
set mouse=v
“打开文件时自动到达上次浏览时的位置
” Only do this part when compiled with support for autocommands
if has(“autocmd”)
” ” In text files, always limit the width of text to 78 characters
autocmd BufRead *.txt set tw=78
” ” When editing a file, always jump to the last cursor position
autocmd BufReadPost *
if line(“‘””) > 0 && line (“‘””) <= line("$") | exe "normal g'"" | endif endif au BufReadPost * if line("'"") > 0|if line(“‘””) <= line("$")|exe("norm '"")|else|exe "norm $"|endif|endif " "其中字符串 “string” 规定了什么要储存。该字符串的语法为一个选项字符跟一个参数. ""选项和参数组成的对子之间由逗号分隔. ""来看一下你可以怎样构建你自己的 viminfo 字符串。首先,选项 ‘ 用于规定你为多 "少个文件保存标记 (a-z)。为此选项挑一个美妙的偶数 (比如 1000). 你的命令现在看 "起来像这样: " ":set viminfo=’1000 " "选项 f 控制是否要储存全局标记 (A-Z 和 0-9)。如果这个选项设为 0,那么什么也不 "存储。如果设为 1 ,或你对 f 选项不作规定, 那么标记就被存储. 你要这个功能, 现 "在你有了: " ":set viminfo=’1000,f1 " "选项 < 控制着每个寄存器内保存几行文本。默认情况下,所有的文本行都被保存. 如果 "设为 0,则什么也不保存。为了避免成千上万行文本被加入你的信息文件 (那些文本可能 "永远也没用,徒然使 Vim 起动得更慢), 你采用 500 行的上限: " ":set viminfo='1000,f1,<500 " "你也许用得着的其它选项: ": 保存命令行历史记录内的行数 "@ 保存输入行历史记录内的行数 "/ 保存搜索历史记录内的行数 "r 可移介质,其中没有任何标记存入 (可用多次) "! 以大写字母开头的全局变数,并且不含有小写字母 "h 起动时解除选项 'hlsearch' 的高亮度显示 "% 缓冲列表 (只有当不带参数起动 Vim 时才还原) "c 用编码 'encoding' 转换文本 "n 用于 viminfo 文件的名称 (必须为最后一项选项) set viminfo='1000,f1,<500

python多线程程序的中断(信号)处理

python程序很容易进行多线程处理,也很好进行signal的处理。但是,在多线程程序中进行信号处理,却不太好搞。我琢磨出了一个可行的办法。
看第一个程序:singlethread.py

#!/usr/bin/python
#coding:utf-8

import signal,os,sys,threading,time
import wk
def sig_exit():
    print "[end time]:"+str(time.time())
    print "exited."
    sys.exit()

def handler(signum, frame):
    print "got an signal",signum,frame
    if signum == 3:
        sig_exit()
    if signum == 2:
        sig_exit()
    if signum == 9:
        sig_exit()
        return None
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
signal.signal(3,handler)




TIME=3

time.sleep(TIME)
print 'normally exit'

运行这个程序,并马上按上Ctrl+C,发现程序这样输出:
<pre>
^Cgot an signal 2
[end time]:1245852618.36
exited.

而不做干扰,让它正常退出时,是这样的:

normally exit

现在我们改进到多线程版本。先写一个线程类:wk.py

import threading,time
class wk(threading.Thread):
def run(self):
for k in xrange(0,4):
print ‘sleep 1 second,’,self,”:”,k
time.sleep(1)

这个线程类啥也不干,就不断输出一个标识 ,然后再歇一秒。再输出,再歇一秒….
主程序:multithreads.py

#!/usr/bin/python
#coding:utf-8

import signal,os,sys,threading,time
from wk import wk

def sig_exit():
print “[end time]:”+str(time.time())
print “exited.”
sys.exit()

def handler(signum, frame):
print “got an signal”,signum,frame
sig_exit()
if signum == 3:
sig_exit()
if signum == 2:
sig_exit()
if signum == 9:
sig_exit()
return None
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
signal.signal(3,handler)
signal.signal(signal.SIGALRM, handler)

threads=[]
for a in xrange(0,4):
temp=wk()
temp.setDaemon(True)
temp.setName(“thread:”+str(a))
temp.start()
threads.append(temp)

for thread in threads:
thread.join()
print “thread joined”,thread

print ‘normally exit’

现在我们运行它,并按下CTL+C.输出结果像这样:

sleep 1 second,sleep 1 second, : 0
sleep 1 second, : 0
: 0
sleep 1 second, : 0
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
^Csleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
^Csleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
got an signal 2
[end time]:1245852879.37
exited.

在按下CTRL+C后,程序并不是马上退出,而是又过了几秒钟才退出。
而运行时不按CTRL+C干扰它时,是这样的输出:

sleep 1 second, : 0
sleep 1 second, : 0
sleep 1 second, : 0
sleep 1 second, : 0
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
thread joined
thread joined
thread joined
thread joined
normally exit
</coolcode>
说明在这个程序里,中断信号能被捕获,但是并不即时。

而最后我的多线程程序是:last.py

#!/usr/bin/python
#coding:utf-8

import signal,os,sys,threading,time
from wk import wk

def sig_exit():
print “[end time]:”+str(time.time())
print “exited.”
sys.exit()

def handler(signum, frame):
print “got an signal”,signum,frame
if signum == 3:
sig_exit()
if signum == 2:
sig_exit()
if signum == 9:
sig_exit()
return None
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
#signal.signal(3,handler)
signal.signal(signal.SIGALRM, handler)

class pause(threading.Thread):
threads=[]
def run(self):
print “pause running”
for thread in self.threads:
thread.join()
print “thread “,thread,” joined”
print “all joined”
signal.alarm(1)

threads=[]
for i in xrange(0,4):
j=wk()
j.setDaemon(True)
j.setName(“thread:”+str(i))
j.start()
threads.append(j)
print “total threads:”,threading.activeCount()

print “current thread:”,threading.activeCount()
print “parent process,main thread,sleeping”

k=pause()
k.setDaemon(True)
k.threads=threads
k.start()
signal.pause()
print “normally exit”

这个程序里,我们的逻辑是这样的:主线程创建了其他工作线程,并且还创建了一个特殊的线程, 这个特殊的线程的任务就着等着其他的工作线程结束(调用了wk类的join方法)。当工作线程都结束后,这个线程就发一个alarm信号。而主线程创建完所有的其他线程后的工作,就是在坐在那儿专门等一个信号。因此当我们按CTRL+C时信号就成功地被捕获了。而没有CTRL+C产生的信号被捕获时,所有工作线程(wk类)结束时也会产生一个alarm信号,也能让程序顺利退出。
这个程序,运行时按下CTRL+C的输出是:

sleep 1 second, : 0
total threads: 2
sleep 1 second, : 0
total threads: 3
sleep 1 second, : 0
total threads: 4
sleep 1 second, : 0
total threads: 5
current thread: 5
parent process,main thread,sleeping
pause running
^Cgot an signal 2
[end time]:1245853073.05
exited.

CTRL+C给程序的信号马上得到了处理。运行这个程序时啥也不做,等着程序结束,输出则是:

sleep 1 second, : 0
total threads: 2
sleep 1 second, : 0
total threads: 3
sleep 1 second, : 0
total threads: 4
sleep 1 second, : 0
total threads: 5
current thread: 5
parent process,main thread,sleeping
pause running
^Cgot an signal 2
[end time]:1245853073.05
exited.
renlu@aragorn:~/Dropbox/Private/devel/python$ py lastprogram.py
sleep 1 second, total threads: : 0
2
sleep 1 second, : 0
total threads: 3
sleep 1 second, : 0
total threads: 4
sleep 1 second, : 0
total threads: 5
current thread: 5
parent process,main thread,sleeping
pause running
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, sleep 1 second, : 2
: 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
thread joined
thread joined
thread joined
thread joined
all joined
got an signal 14
normally exit

测试FusionIO:strict_sync太秀逗了…

这是一篇译文,原文地址是:   http://www.mysqlperformanceblog.com/2009/06/15/testing-fusionio-strict_sync-is-too-strict/

随着新的更新FusionIO驱动的更新,我能够在我的戴尔R900与Ubuntu 8.10上进行尝鲜,而不再需要痛苦地编译驱动或是降级kernel.现在我决定测试一下strict_sync模式。

据我所知FusionIO默认情况下,比如英特尔的SSD ,是对应用程序“撒谎”了,fsync()并不是真正的发生了,它仍然只是提交到了内存而不是最终的磁盘。FusionIO还有一个“ strict_sync ”模式,可以保证fsync函数可靠地操作。

好啊兄弟,让我们来压一下性能—通常我在100w数据(约9GB数据),O_DIRECT模式下开着3GB的buffer_pool来搞这个测试。
原始测试数量参见这里
pub
结果用TPM (每分钟的事务数)表示 ,这样更清楚一些。图形显示,结果是是随着时间[X轴]不断变化 。
这个图形已经很明显,我都不需要再用文字来说明了。。。

但是我没有测试,在断电的情况下,在默认模式下处理、结束事务的情况。这个需要读者您检查一下。

怎样用一行脚本美化/etc/my.cnf文件

原文地址:http://www.mysqlperformanceblog.com/2009/06/15/how-to-pretty-print-mycnf-with-a-one-liner/
当我在一台服务器上转悠时,我会经常想看看/etc/my.cnf文件格式,当然是想看格化美观,没有注释的。这样的一行Perl就能将美化输出文件:

1.perl -ne ‘m/^([^#][^s=]+)s*(=.*|)/ && printf(“%-35s%sn”, $1, $2)’ /etc/my.cnf
2.[client]
3.port = 3306
4.socket = /var/run/mysqld/mysqld.sock
5.[ mysqld_safe ]
6.socket = /var/run/mysqld/mysqld.sock
7.nice = 0
8.[ mysqld ]
9.user = mysql
10.pid-file = /var/run/mysqld/mysqld.pid
11.socket = /var/run/mysqld/mysqld.sock
12.port = 3306
13…..

缓慢的drop table 操作

原文地址:http://www.mysqlperformanceblog.com/2009/06/16/slow-drop-table/

大家都知道,Ext3并不是最有效的文件系统,例如,删除文件会非常缓慢(那真是一个痛苦的过程,不是吗老兄?),造成大量的随机I / O。然而事实上,有时候它比你想象的更能影响MySQL的性能。那么,什么时候会发生,又为什么会发生呢?

当您运行DROP TABLE时,会有好几件事情需要去做:对表进行write lock,这样它不会被其他线程使用;存储引擎删除数据文件;当然,最后MySQL会删除表定义文件(.frm文件)。这还不是所有的事,还有另外一件事需要去做:

  1. VOID(pthread_mutex_lock(&LOCK_open));
  2. error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
  3. pthread_mutex_unlock(&LOCK_open);

这整段删除表操作的代码都被LOCK_open互斥信号量所包围。这个互斥信号量在MySQL中不少地方都用到过,但主要是表在开启或关闭的时候。这意味着,当LOCK_open锁定时,没有查询语句可以执行,因为他们阻止任何访问。

这就解释了在ext3文件系统上删除10GB的文件何时成为了痛苦的等待的开始。删除10GB的文件将持续一段时间,如果这是一个MySQL表,这段时间mutex里将会一直存在,而这个互斥会拖延所有查询。

代码:

  1. +—–+——+———–+——+———+——+ —————-+——————————— —————+
  2. | Id | User | Host | db | Command | Time | State | Info |
  3. +—–+——+———–+——+———+——+ —————-+——————————— —————+
  4. | 1 | root | localhost | test | Query | 7 | NULL | drop table large_table |
  5. | 329 | root | localhost | test | Query | 7 | Opening tables | select sql_no_cache * from other_table limit 1 |
  6. +—–+——+———–+——+———+——+ —————-+——————————— —————+

我尝试了一些替代的办法,让MySQL来在DROP TABLE时删除小文件,以尽量减少影响,如:

  • TRUNCATE TABLE large_table; ALTER TABLE large_table ENGINE=…; DROP TABLE large_table;
  • TRUNCATE TABLE large_table; OPTIMIZE TABLE large_table; DROP TABLE large_table;

不幸的是,原来所有管理指令:ALTER TABLE <ALTER ALTER TABLEOPTIMIZE TABLE实际都一样,或是在旧的表文件删除时使用了其他的LOCK_open互斥信号锁。

代码:

  1. | 3 | root | localhost | test | Query | 7 | rename result table | ALTER TABLE large_table ENGINE=MyISAM |
  2. | 679 | root | localhost | test | Query | 6 | Opening tables | select * from other_table limit 1 |

唯一的选择似乎就只能是改变文件系统了。例如,换成处理文件删除更有效的XFS文件系统。

EXT3

代码:

  1. mysql> drop table large_table;
  2. Query OK, 0 rows affected (7.44 sec)

的xfs

代码:

  1. mysql> drop table large_table;
  2. Query OK, 0 rows affected (0.29 sec)

一个MySQL的内部操作可能更好一点:可以通过先重命名对应的数据文件,再在没有互斥信号锁的情况下删除物理文件。但是事实上可能没有那么简单,因为实际的删除操作是由存储引擎来完成的,因此不是MySQL的代码能控制的。

这肯定不是一个共同的情况,但是有时候(虽然我们极其不愿)确实可能会让任何人头痛(例如,删除一个老的不再使用的表) 。

这里绍明同学说应该翻译成:这不是一个常见的情况,但是它可能会在最不期望出现的时候成为一个问题(例如 删除没有使用的旧表).


后附:

一个评论回复说:

从一个完全不同的领域的解决办法。

mythtv (电视记录系统)开发者们在ext3系统上删除大型文件时,通过“缓慢删除”功能取得更好的效果。一般来说,电视录音大概1 – 12GB每小时,所以一部电影可以20 + GB大小的文件。如果没有该功能,删除文件操作将锁定ext3整个系统约20-30秒。

“慢删除”只是在后台执行将文件中的块清空的操作。

另一个评论说:

我应该指出,这并不只适用于MyISAM表,对于InnoDB表,在innodb_file_per_table模式下也一样。
我最近刚跟客户做了个spoke,他们几乎无法删掉一个400G的表,因为这个操作阻塞了很长时间。。

好色的程序员:怎么加上彩色显示

问题列表

1.终端如何支持显示彩色
     现代终端基本上都已经支持彩色显示了。【8色的显示屏是什么时候发明的?】 您可以在bash下用这段来试试:<coolcode>
echo -e “33[40;32mcolored text33[0;0m”
</coolcode>
如果这里出来的是彩色文字,那就说明您的终端是支持彩色显示的。如是没有出来彩色文字,那就,改您的终端类型。一般情况下您的终端软件可选的有vt100,vt102,vt220,vt320,linux,xterm等几种。我一般选linux.
2.终端颜色和颜色表:
   要在终端中显示彩色文字,需要这样输出<coolcode>
ESC[attr;frontcolor;backgroundcolor;m

要加彩色的文字。
</coolcode>

ESC是ESCAPE键,它的ASC码是十进制的27,八进制的33.所以我们用echo -e “33…”来输入。attr是要给文字设置的属性代号,frontcolor是文字颜色代号,backgroundcolor是文字背景色代码。这些代号及意义如下:
<coolcode>

  前景             背景              颜色 
   ————————————— 
   30                40               黑色 
   31                41               紅色 
   32                42               綠色 
   33                43               黃色 
   34                44               藍色 
   35                45               紫紅色 
   36                46               青藍色 
   37                47               白色 

   代码              意义 
   ————————- 
   0                 OFF 
   1                 高亮显示 
   4                 underline 
   5                 闪烁 
   7                 反白显示 
   8                 不可见 
</coolcode> 
2.PS1,ls ,grep 如何加彩色
  PS1是bash一个特殊的变量,用来指定提示符。我们只要修改它的值就可以指定提示符如何显示。在这里h表示主机名,u表示当前用户,w表示当前目录。我的设置是:
<coolcode>export PS1=”[e[36;1m]u@[e[32;1m]H>:w>[e[0m]”</coolcode> 

这里bash的提示符已经变成彩色了,但是ls的输出还不是彩色的。也很简单,man一下就知道了,在linux下,

<coolcode>alias ls=”ls –color=auto”</coolcode>就行了。在FreeBSD下,<coolcode>alias ls=”ls -G”</coolcode>即可。

grep也是支持彩色的:
<coolcode>
alias grep=”grep –color=auto”
</coolcode> 
好了,现在我们可以把~/.bashrc文件 改一下:
<coolcode>
export PS1=”[e[36;1m]u@[e[32;1m]H>:w>[e[0m]”
alias ls=”ls –color=auto”
alias grep=”grep –color=auto”
</coolcode> 
 

2.svn diff怎么加彩色:
我写了一个脚本,放在http://xurenlu.googlecode.com/files/svncolor.py这里。只需要svn diff|python svncolor.py即可把svn diff的结果转成彩色的。

3.git diff怎么加彩色
git diff加颜色非常简单:修改.git/config,加上
<coolcode>
[diff]
    color = auto 
</coolcode> 

4.vim 怎么支持彩色
非常简单,如果是php文件:
<coolcode>
:set ft=php
:set syntax
</coolcode> 
就行了。 

6.怎么去彩色
为什么要去颜色呢,因为有时候我们需要把一些输出重定向到vim中间,这时在vim中会出现很多控制字符。所以我们要再转成黑底白字。
我这里也有一个脚本。 
<coolcode>
#!/usr/bin/python
import sys,re
PESC=chr(27)
nocolor_re=re.compile(PESC+'[[d;]+m’)
if __name__==”__main__”:
    while(True):
        line=sys.stdin.readline()
        if not line: break
        line=line.replace(“n”,””)
        print nocolor_re.sub(“”,line)
</coolcode>

PHP注释查看器

今天用着pydoc用的特爽,特希望能够找到一个php下的查看注释的工具。php生成文档倒是有一个phpdocument,另外还有一个给c/c++生成文档的doxygen也能用来给php生成文档。可是就是都太麻烦。于是我的用py写了一个查看php的注释的,能够逐行读入php代码,区分用/*来给出的注释。目前只能查看phpdocument方式的注释,另外,类里面的函数不能正确给出类名。不过在很多情况下够用了。关键是小巧。 

请在http://xurenlu.googlecode.com/files/phpcomment.py 这里下载。使用很简单。用 phpcomment.py < phpfile  或 phpcomment.py phpfile即可。

 

完整解决vim不能记住上次的位置的问题

症状:
不能记住上次的位置: vim a 移到到第n行。关闭,再打开.vim 又回到了第1行。
跨文件复制粘贴时,报“寄存器里没有东西”.在文件a里复制,退出,打开b文件按P,无法复制。

解决:

1.在vim中输命令

:version

确认编译选项中有+viminfo.
2.若是ubuntu系统,请用update-alternatives –config vim 查看vim的具体版本。ubuntu有vim有vim.tiny,vim.gnome,vim.gtk等多个版本。如果是vim.tiny,将不支持 viminfo.[vim.tidy不支持很多特性,建议装完ubuntu即切换到vim.gnome.命令:update-alternatives –config vim]

3.在~/.vimrc文件中确认加上了:


au BufReadPost * if line(”‘””) > 0|if line(”‘””) <= line(”$”)|exe(”norm ‘”")|else|exe “norm $”|endif|endifset viminfo=’1000,f1,<500

4.请ls ~/.viminfo ,结果大致如下:

-rw——- 1 renlu renlu 7.5K 2009-06-05 14:29 /home/renlu/.viminfo

请确保:

a.用户属主是你。
b.文件属性是–rw——..,如果不是,请chmod 0600 ~/.viminfo

附:
今天遇到的问题是/home/$USER 目录满了,无法写入东西,.viminfo文件也不再被允许写入。这样跟.viminfo文件权限问题的表现是一样的。

hyer开发笔记之:最大页面数的获取

搞垂直搜索(好吧,我承认我说得有点太高雅:搞网页采集)时,一般分这样两步:

  • 搞到列表页,读出所有待抓取的内容页面。
  • 挨个读取内容页面,解析出需要的信息,比如做购特搜索时需要采集商品名称,价格,描述,商品图片等

现在首先要解决的搞到列表页。拿到列表页时,有的同志很认真,就顺着那个下一页又一次地地抓取所有列表页面。其实不是特别必要。比如,bj.58.com的租房信息列表页,分了10000多页,光遍历这些列表页就需要好久。
hyer的处理方式是,把取到列表面的最大页面数做为一个任务,单独拿出来由一个专有模块去执行。逻辑是这样的:
首页你需要人工分析出列表面的URL的特征。58的那个很简单,一下子就能出来:
<coolcode>
http://bj.58.com/zufang/pn%d/
</coolcode>
%d是分页数。
其次我们要找的时,找出一个字串,在页面数过大(就是一直翻下一页,发现没有下一页可以翻的那个识别串)。这里58的页面估计是用.net的控件拖的,所以就是访问一个不存在的分页,比如第10万页,他也有下一页的链的妆可以翻。这时我们取的是列表项里的一个字符串:
<coolcode>
“onmouseout=”this.style.background=’#F7F9FE”
</coolcode>
[顺便说一下,58的前端设计同学,这样写javascript不太好呀。].
接下来,我们需要一页页地翻。(您要有疑问了,咦,说白了您也还是一页页地翻啊!)
NO!
我们是用二分法的思维来试!首先我们一次跳2048页,从第一页,依次试了1,2048,4097等页.
<coolcode>
page: 1  is not max page
page: 2049  is not max page
page: 4097  is not max page
page: 6145  is not max page
page: 8193  is not max page
page: 10241  is not max page
page number  12289  too big..
<coolcode>
然后发现12289页无法找到这个特征字串。现在我们知道,这个最大页码至少是10241了。接下来,我们一次跳过512个页码,分别访问10753,11265..页。

如此类推,一直到每次跳过1页时,就能很精确地找到最大页码了。好了,接下来我们的任务管理器就根据这个最大页码,决定启动多少个fake browser来要假装用户去读这1w多个列表页了。

未完,待续。