MySQL中Query Cache的华丽外衣

作者:Lightning@小宝 发布时间:August 31, 2009 分类:MySQl学习笔记

作者:苏普

当你的数据库打开了Query Cache(简称QC)功能后,数据库在执行SELECT语句时,会将其结果放到QC中,当下一次处理同样的SELECT请求时,数据库就会从QC取得结果,而不需要去数据表中查询。

3860690717_aefef292dc_o.png

 

在这个“Cache为王”的时代,我们总是通过不同的方式去缓存我们的结果从而提高响应效率,但一个缓存机制是否有效,效果如何,却是一个需要好好思考的问题。在MySQL中的Query Cache就是一个适用较少情况的缓存机制。在上图中,如果缓存命中率非常高的话,有测试表明在极端情况下可以提高效率238%[1]。但实际情况如何?Query Cache有如下规则,如果数据表被更改,那么和这个数据表相关的全部Cache全部都会无效,并删除之。这里“数据表更改”包括: INSERTUPDATEDELETETRUNCATEALTER TABLEDROP TABLE, orDROP DATABASE等。举个例子,如果数据表posts访问频繁,那么意味着它的很多数据会被QC缓存起来,但是每一次posts数据表的更新,无论更新是不是影响到了cache的数据,都会将全部和posts表相关的cache清除。如果你的数据表更新频繁的话,那么Query Cache将会成为系统的负担。有实验表明,糟糕时,QC会降低系统13%[1]的处理能力。

如果你的应用对数据库的更新很少,那么QC将会作用显著。比较典型的如博客系统,一般博客更新相对较慢,数据表相对稳定不变,这时候QC的作用会比较明显。

再如,一个更新频繁的BBS系统。下面是一个实际运行的论坛数据库的状态参数:

QCache_hit5280438
QCache_insert8008948
Qcache_not_cache95372
Com select8104159

可以看到,数据库一共往QC中写入了约800W次缓存,但是实际命中的只有约500W次。也就是说,每一个缓存的使用率约为0.66次。很难说,该缓存的作用是否大于QC系统所带来的开销。但是有一点是很肯定的,QC缓存的作用是很微小的,如果应用层能够实现缓存,将可以忽略QC的效果。

————-下面是关于QC的一些其他细节—————–

一、Query Cache相关参数:

  • query_cache_size QC占用空间大小,通过将其设置为0关闭QC功能
  • query_cache_type 0表示关闭QC;1表示正常缓存;2表示SQL_CACHE才缓存
  • query_cache_limit 最大缓存结果集
  • query_cache_min_res_unit 手册上说,QC会按照这个值分配缓存block的大小。
  • Qcache_lowmem_prunes 这是一个状态变量(show status),当缓存空间不够需要释放旧的缓存时,该值会自增。

二、Query Cache观察:

CREATE TABLE t1(id INT,var1 varchar(10));
	//Com_select:8	Qcache_hits:1
INSERT INTO t1 VALUES(1,’WWW’);
	//Com_select:8	Qcache_hits:1
SELECT * FROM t1 WHERE id=1;
	//Com_select:9	Qcache_hits:1
SELECT * FROM t1 WHERE id=1;
	//Com_select:9	Qcache_hits:2 Qcache_queries_in_cache:1
INSERT INTO t1 VALUES(2,’RRRR’);
	//Com_select:9	Qcache_hits:2 Qcache_queries_in_cache:0
SELECT * FROM t1 WHERE id=1; //INSERT后Cache失效
	//Com_select:10  Qcache_hits:2 Qcache_queries_in_cache:1

参考:

  1. http://dev.mysql.com/doc/refman/5.0/en/query-cache.html
  2. http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html
  3. http://www.mysqlperformanceblog.com/2006/07/27/mysql-query-cache/

 

java使用bdb手记(Berkeley DB Java api记录)

作者:Lightning@小宝 发布时间:August 28, 2009 分类:Python/Java/Erlang学习

在线Berkeley DB Java Edition API:
http://www.oracle.com/technology/documentation/berkeley-db/je/java/index.html
Berkeley DB是一个开放源代码的内嵌式数据库管理系统,能够为应用程序提供高性能的数据管理服务。应用它程序员只需要调用一些简单的API就可以完成对数据的访问和管理。与常用的数据库管理系统(如MySQL和Oracle等)有所不同,在Berkeley DB中并没有数据库服务器的概念。应用程序不需要事先同数据库服务建立起网络连接,而是通过内嵌在程序中的Berkeley DB函数库来完成对数据的保存、查询、修改和删除等操作。
用java来操作BDB,需要jar包je-3.3.62.jar

Java操作bdb数据库,记录一下cc0cc的代码:

import java.io.File;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

public class MyBerkeleyDB {

	private Environment env;
	private Database db;
	
	public MyBerkeleyDB() {
	
	}

	public void setUp(String path, long cacheSize) {
		EnvironmentConfig envConfig = new EnvironmentConfig();
		envConfig.setAllowCreate(true);
		envConfig.setCacheSize(cacheSize);
		try {
			env = new Environment(new File(path),envConfig);
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}
	
	public void open(String dbName) {
		DatabaseConfig dbConfig = new DatabaseConfig();
		dbConfig.setAllowCreate(true);
		try {
			db = env.openDatabase(null, dbName, dbConfig);
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}
	
	public void close() {
		try {
			if(db != null) {
				db.close();
			}
			if(env != null) {
				env.close();
			}
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}
	
	public String get(String key) throws Exception {
		DatabaseEntry queryKey = new DatabaseEntry();
		DatabaseEntry value = new DatabaseEntry();
		queryKey.setData(key.getBytes(”UTF-8″));
		
		OperationStatus status = db.get(null, queryKey, value,
		LockMode.DEFAULT);
		if (status == OperationStatus.SUCCESS) {
			return new String(value.getData());
		}
		return null;
	}
	
	public boolean put(String key, String value) throws Exception {
		byte[] theKey = key.getBytes(”UTF-8″);
		byte[] theValue = value.getBytes(”UTF-8″);
		OperationStatus status = db.put(null, new DatabaseEntry(theKey),
		new DatabaseEntry(theValue));
		if(status == OperationStatus.SUCCESS) {
			return true;
		}
		return false;
	}

	public static void main(String[] args) {
		MyBerkeleyDB mbdb = new MyBerkeleyDB();
		mbdb.setUp(”C:\\bdb”, 1000000);
		mbdb.open(”myDB”);
		System.out.println(”开始向Berkeley DB中存入数据…”);
		for(int i=0; i<20; i++) {
			try {
				String key = “myKey”+i;
				String value = “myValue”+i;
				System.out.println(”[" + key + ":" + value + "]“);
				mbdb.put(key , value);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		mbdb.close();

	}
}

MySQL中的字符与字节

作者:Lightning@小宝 发布时间:August 28, 2009 分类:MySQl学习笔记

进入mysql client:

创建测试表:

mysql> create table t_char_and_binary(
    -> str char(1) not null default '',
    -> bin_str binary(1) not null default ''
    -> )engine=innodb;
Query OK, 0 rows affected (0.02 sec)

插入测试数据:

mysql> insert into t_char_and_binary values('w','w');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_char_and_binary values('学','学');
Query OK, 1 row affected, 1 warning (0.01 sec)

查看刚才插入的数据:

mysql> select * from t_char_and_binary;
+-----+---------+
| str | bin_str |
+-----+---------+
| w   | w       | 
| 学  | 堠      | 
+-----+---------+

很明显bin_str中文乱码了, 中文gbk占两个字节,utf-8占用三个字节

char代表字符,不管中文英文;binary代表字节,用二进制表示一字节: 00000000-11111111 有255种

体验了一下Google.Gears

作者:Lightning@小宝 发布时间:August 28, 2009 分类:JavaScript学习笔记

GoogleGears能够提供客户端存储及离线访问功能极大的丰富了Brower Client的功能体验;
现在已知国内在使用GoogleGears的有:QQ空间/校内网

GoogleGears 主要包含3个模块:
1. 本地 web 服务器(用于提供 HTML, JavaScript, 图片等的访问请求)
2. 数据库
3. WorkerPool
通过异步的方式在后台进行资源访问的操作(比如同步本地用户数据到服务器),
使浏览器程序保持快速响应。

初始化code:

gears_init.js
(function() {
  // We are already defined. Hooray!
  if (window.google && google.gears) {
    return;
  }
  var factory = null;

  // Firefox
  if (typeof GearsFactory != 'undefined') {
    factory = new GearsFactory();
  } else {
    // IE
    try {
      factory = new ActiveXObject('Gears.Factory');
      // privateSetGlobalObject is only required and supported on IE Mobile on
      // WinCE.
      if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
        factory.privateSetGlobalObject(this);
      }
    } catch (e) {
      // Safari
      if ((typeof navigator.mimeTypes != 'undefined')
           && navigator.mimeTypes["application/x-googlegears"]) {
        factory = document.createElement("object");
        factory.style.display = "none";
        factory.width = 0;
        factory.height = 0;
        factory.type = "application/x-googlegears";
        document.documentElement.appendChild(factory);
      }
    }
  }
  // *Do not* define any objects if Gears is not installed. This mimics the
  // behavior of Gears defining the objects in the future.
  if (!factory) {
    return;
  }
  // Now set up the objects, being careful not to overwrite anything.
  // Note: In Internet Explorer for Windows Mobile, you can't add properties to
  // the window object. However, global objects are automatically added as
  // properties of the window object in all browsers.
  if (!window.google) {
    google = {};
  }
  if (!google.gears) {
    google.gears = {factory: factory};
  }
})();

数据库应用Demo:http://code.google.com/apis/gears/samples/hello_world_database.html
代码解说:
首先引入初始化代码:

loadJavascript('gears_init.js');
//数据库连接对象
var db;
init();
//打开本页面对应的本地数据库
function init(){
    if (!window.google || !google.gears) {
    return;
  }
  try {
    db = google.gears.factory.create('beta.database', '1.0');
  } catch (ex) {
    setError('Could not create database: ' + ex.message);
  }
  if (db) {
    db.open('database-demo'); // 打开数据库
    // 创建表的语法
    db.execute('create table if not exists Demo' +
               ' (Phrase varchar(255), Timestamp int)');
  }
}

获取最新的三条记录,但删除其他老记录

var recentPhrases = ['', '', ''];
try {
 // 这里返回的实际上是一个记录集的游标(cursor),和 ASP 的经典写法很类似。
 var rs = db.execute('select * from Demo order by Timestamp desc');
 var index = 0;
 while (rs.isValidRow()) {
  if (index < 3) {
   recentPhrases[index] = rs.field(0);
  } else {
   // 这里可以看到 Tempstamp(时间戳)被当作主键使用了。
   db.execute('delete from Demo where Timestamp=?', [rs.field(1)]);
  }
  ++index;
  rs.next();
 }
 rs.close();
} catch (e) {
 throw new Error(e.message);
}

用户提交数据,插入数据库代码

function handleSubmit() {
  if (!google.gears.factory || !db) {
    return;
  }

  var elm = document.getElementById('submitValue');
  var phrase = elm.value;
  // 注意 getTime() 方法返回的是日期对象相当于某个基准时间的毫秒数,是一个大整数
  var currTime = new Date().getTime();

  // 插入新记录
  // Gears 数据库能自动转义/反转义插入的值。
  // (The Gears database automatically escapes/unescapes inserted values.)
  db.execute('insert into Demo values (?, ?)', [phrase, currTime]);

  // Update the UI.
  elm.value = '';
  displayRecentPhrases();
}

其主页地址在:http://code.google.com/apis/gears/
网上论坛:http://groups.google.com/group/google-gears/

phpunit测试驱动开发Example

作者:Lightning@小宝 发布时间:August 27, 2009 分类:php经验技巧

/**
* @author 小宝
* @site: http:www.daxi8.cn
* @desc: 原创内容,转载请注明出处,及其包含以上内容。
*/

require_once 'PHPUnit/Framework.php';
class DataTest extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider provider #使用@dataProvider标记provider方法为此方法提供数据
     */
    public function testAdd($a, $b, $c){
        $this->assertEquals($c, $a+$b);
    }

    //供给者, 返回值只能是数组,或者实现了Iterator的对象
    public function provider(){
        return array(
            array(0, 0, 0),          array(0, 1, 1),          array(1, 0, 1),          array(1, 1, 3)
        );
    }
}

未完待续!

  1. 页码:
  2. 1
  3. 2
  4. 3
  5. 4
  6. ...
  7. 14
我要报警