sqlite3连接查询和多次select的对比

作者:dawncold 发布时间:May 14, 2012 分类:技术

通过todo_meta把todo和user联系起来,要查出userid为0~6的所有todo。随机了10W条todo数据进去。

左外连接查询比两次select快10~20%左右。


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

import sqlite3
import os
import time
import random

def connect():
	return sqlite3.connect('./test.db')


def insertProgress(conn, user_id):
	cur = conn.execute('INSERT INTO todo(title, date) VALUES(?,?)', ['just test!!!', time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())])
	conn.execute('INSERT INTO todo_meta(todo_id, user_id) VALUES(?,?)', [cur.lastrowid, user_id])


def insertManyData(conn):
	#reset database
	os.system('sqlite3 test.db < schema.sql')
	
	conn.cursor()
	counts = [0,0,0,0,0,0]
	for i in xrange(100000):
		userid = random.choice([0, 1, 2, 3, 4, 5])
		counts[userid] += 1
		insertProgress(conn, userid)
	conn.commit()
	conn.close()
	print counts

def selectUsingLeftOuterJoin(conn, user_id):
	conn.cursor()
	cur = conn.execute('SELECT t.title, t.date \
											FROM todo t LEFT OUTER JOIN todo_meta tm \
											ON tm.todo_id = t.id\
											WHERE tm.user_id = ?', [user_id])

def selectTwoTimes(conn, user_id):
	conn.cursor()
	cur = conn.execute('SELECT todo_id FROM todo_meta WHERE user_id = ?', [user_id])
	for tid in [row[0] for row in cur.fetchall()]:
		cur = conn.execute('SELECT title, date FROM todo WHERE id = ?', [tid])

if __name__ == "__main__":
	uids = [0, 1, 2, 3, 4, 5]
	insert_time_start = time.time()
	insertManyData(connect())
	print "Insert Time: %f" % (time.time() - insert_time_start)
	select_ULOJ_start = time.time()
	for uid in uids:
		selectUsingLeftOuterJoin(connect(), uid)
	print "Select Using Left Outer Join time: %f" % (time.time() - select_ULOJ_start)
	select_two_times = time.time()
	for uid in uids:
			selectTwoTimes(connect(), uid)
	print "Select Two Times time: %f" % (time.time() - select_two_times)

schema:


drop table if exists todo;
drop table if exists user;
drop table if exists todo_meta;
create table todo (
	id integer primary key autoincrement,
	title string not null,
	date datetime not null
);
create table user (
	id integer primary key autoincrement,
	email string not null,
	password string not null,
	nickname string not null,
	salt string not null
);
create table todo_meta (
	todo_id integer,
	user_id integer,
	foreign key(todo_id) references todo(id),
	foreign key(user_id) references user(id)
);

启动脚本就会创建数据库并开始测试。

sqlite3的rowcount

作者:dawncold 发布时间:May 14, 2012 分类:技术

最近写了一个todo的webapp,在用户登陆的时候是select数据库中的内容进行对比判断,当然如果select的内容是0那就表示用户登陆失败了,可能账号或者密码写错了,数据库用的sqlite3,在python的api中发现有cursor.rowcount可用,于是就这么判断一下是不是有数据被select出来了,没想到这样判断是错误的。

select的rowcount永远为-1,哎,这里着实坑了我一番啊~

只好cursor.fetchone()先,然后判断得到的内容是不是None。

这里得到的答案。

web.py真不好用

作者:dawncold 发布时间:May 6, 2012 分类:技术

本来做了个一个todo的app感觉python写web app真得好快啊,于是想加入一个user的功能,这样注册的用户就可以写自己的todo了,不过这么一加才感觉到web.py真不好用了,特别是session,还有templates也不怎么好用,官方的文档不知道为何也不给个完整版的,api只是写出来了,但基本都不说是什么作用,想清楚知道运行机制那就得看源代码了,还好不“那么”长!

哎,暂时就放一下web.py吧!到头来过度依赖框架绝对不是什么好事,嗯,不是什么好兆头现在的我!

用python备份mysql

作者:dawncold 发布时间:April 27, 2012 分类:技术

备份数据库的重要性不想多说了。


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

import os
import sys
from datetime import *
import time

#mysql's path
mysql_path = '/usr/local/mysql/bin/'
#edit this if your mysql username and password is not like this:
mysql_username = 'root'
mysql_password = 'xxxxxx'
#backup path
backup_path = 'mysqlbackup/'

def validate_backup_path():
	if os.path.exists(backup_path) == False:
		print "I create a directory here: %s " % backup_path
		os.mkdir(backup_path)

def backup_all_databases():
	filename = "all_%s.sql" % (datetime.utcfromtimestamp(time.time()))
	os.system("%smysqldump -u%s -p%s --all-databases > '%s%s'" % (mysql_path, mysql_username, mysql_password, backup_path, filename))

if __name__ == "__main__":
	validate_backup_path()
	backup_all_databases()
	print "finish!!!"

这个是修改了一次的备份脚本,本来是分数据库备份的,无奈制定了分数据库备份需要输入密码,这就不容易加入cron来自动完成了,不过听说在my.cnf中加入mysqldump的设置可以避免输入账号密码,这也算是一个办法吧,不过还是本着简化的思想,只导出所有数据库出来就好,配合着上一篇的dropbox自动备份,这样VPS的灾备就稍稍好些了:)

dropbox自动备份VPS

作者:dawncold 发布时间:April 27, 2012 分类:技术

这里看过的文章,感觉很不错,于是发表过来,但发现有点问题,我就自己再改改。

安装linux下的dropbox(我的是32为系统,如果是64位在下面地址末尾加上“_64”即可):


wget -O dropbox.tar.gz http://www.dropbox.com/download?plat=lnx.x86

解压后在.dropbox-dist目录中有dropboxd可执行文件,让其在后台执行(就是在执行文件后面加“&”符号)


~/.dropbox-dist/dropboxd &

此后会出现一个地址,你得复制出来然后在浏览器中打开,之后就是注册或者登陆dropbox,这样就激活了在这台机器上的dropbox,就可以同步文件了。

把需要同步备份的文件软连接到Dropbox这个目录中:


cd ~/Dropbox
ln -s /home/wwwroot/
。。。

此时dropbox已经在帮你同步了,你可以通过web端观察。

我看到的文章中带着一个自动运行的脚本,用sh写的,我发现在主机上运行没反应,不会sh,会点python,于是我改写了一下,也是可用的:


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

import sys
import os

def start():
	print "Starting Dropbox..."
	os.system("~/.dropbox-dist/dropboxd &")

	
def stop():
	print "Stoping Dropbox..."
	os.system("pkill dropbox")


def restart():
	stop()
	start()


if __name__ == "__main__":
	action = sys.argv[1]
	print "now action: %s" % action
	if action == 'start':
		start()
	elif action == "stop":
		stop()
	elif action == "restart":
		restart()
	else:
		print "Bad arguments!"

相应的crontab配置文件中这样写就好了:


#auto dropbox
0 4 * * * python /root/dropbox.py restart
0 5 * * * python /root/dropbox.py stop

如果没装crontab(极少情况),这样(也许你用apt-get来做这件事,我的是centos系统,用yum了):


yum -y install crontab

python让我很快乐:)

一开始在python用的是exec来执行命令发现不可用,于是用了os.system,查看pydoc才发现exec是执行python code用的……惭愧!