« 2010年7月的文章归档

【高性能MySql】读书笔记 二

1.基准测试:用来测量系统的整体性能

1)集成式测试:将整 个应用(包括mysql)做为整体进行测试

2)单组件式测试:单独测试mysql

2.性能测试:…

3.测试指标

1)单位时间的事务处理量

2)响应时间或时延

3)扩展性

4)并发性

4.集成式测试工具

1)apache ab

2)http_load

3)JMeter

5.单组件式测试工具

1)mysqlslap

2)sysbench

3)Database Test Suite

4)MySQL Benchmark Suite(sql-bench)

5)Super Smack

6.性能分析

1)PHP日志类,class.Timer.php,使用内建函数:getrusage();

2)慢日志

7.日志分析工具

1)Mysqldumpslow

2)Mysql_slow_log_filter

3)Mysql_slow_log_parser

4)Mysqlsla

8.使用SHOW STATUS分析查询

9.SHOW PROFILE

【高性能MySql】读书笔记 一

题外话:虽然这本书翻译的不尽如人意,但不可否认这是一本MySql方面的顶级好书。有的话虽然是汉字国语,但看个N遍还不得其解,这个翻译…唉!为了以后能轻松点查阅,现提重点想记的做些笔记。

1.MySql的逻辑架构

2.并发控制:读锁(共享锁),写锁(排他锁)

3.事务

START TRANSACTION

COMMIT

ROLLBACK

4.事务日志 ——预写式日志

5.AUTOCOMMIT

SHOW VARIABLES LIKE ‘AUTOCOMMIT’

SET AUTOCOMMIT = 1

6.多版本并发控制(MVCC)

7. “.frm”文件存储表定义

8.SHOW TABLE STATUS LIKE ‘user’\G;

其中Row_format可能是Dynamic,Fixed,Compressed

9.MyISAM特性

手工修复:CHECK TABLE mytable和REPAIR TABLE mytable。离线时用myisamchk命令行工具检查和修复表。

其中索引的特性:可基于BOLB和TEXT类型列前500个字符创建相关索引

延迟更新索引:DELAY_KEY_WRITE

10.Memory引擎

不支持TEXT或BLOB字段类型,如果含TEXT或BOLB字段类型或中间数据非常大,将会转成MyISAM表

只支持固定大小行

11.读写分离与合并表

12.表类型转换

1)ALTER TABLE mytable ENGINE = Falcon

缺点:源表被读加锁,旧表到新表逐行复制,占用大量IO,耗费大量时间

2)转储和导入,用mysqldump导出相改语句再导入

3)CREATE TABL innodb_table LIKE myisan_table;

ALTER TABLE innodb_table ENGINE =InnoDB;

INSERT INTO innodb_table SELECT * FROM myisam_table;

缺点:可以在数据量小时用,数据量大时,日志变得很庞大,可以采用事务的方式:

START TRANSACTION;

INSERT INTO innodb_table SELECT * FROM myisam_table WHERE id BETWEEN x AND y;

COMMIT;

看mysql5.1手册做的一点笔记

1. SET @var_name = expr [, @var_name = expr] …
对于SET:
mysql> SET @t1=0, @t2=0, @t3=0;
用语句代替SET来为用户变量分配一个值
mysql> SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
注释:在SELECT语句中,表达式发送到客户端后才进行计算。这说明在HAVING、GROUP BY或者ORDER BY子句中,不能使用包含SELECT列表中所设的变量的表达式
2. mysql> SHOW CHARACTER SET; #字符集
mysql> SHOW COLLATION LIKE ‘latin1%’; #较对规则
shell> mysqld –default-character-set=latin1 \
–default-collation=latin1_swedish_ci #服务器
#建数据库时候
CREATE DATABASE db_name
[[DEFAULT] CHARACTER SET charset_name]
[[DEFAULT] COLLATE collation_name]

ALTER DATABASE db_name
[[DEFAULT] CHARACTER SET charset_name]
[[DEFAULT] COLLATE collation_name]
3. SET NAMES ‘x’
等价于
mysql> SET character_set_client = x;
mysql> SET character_set_results = x;
mysql> SET character_set_connection = x;
4. SERIAL是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的一个别名。
5. TINYINT 28-1 28*1-1
SMALLINT 216-1 28*2-1
MEDIUMINT 224-1 28*3-1
INT 232-1 28*4-1
BIGINT 264-1 28*8-1
6. 没有varchar, text, blob等字段的表是静态表,反之是动态表,静态表的检索效率要比动态表好若干倍
7. 列中有一个varchar会自动把char转换成varchar , 而当varchar长度小于4时,自动的把varchar转换成char
8. CHAR(M)M <=255 , VARCHAR(M) M<=65535 , BLOB[(M)] M<=65535 , TEXT[(M)] M<=65535
9. ENUM('value1','value2',...) 枚举类型 ENUM值在内部用整数表示。
10. SET('value1','value2',...) WHERE FIND_IN_SET('value',set_col)>0 或 set_col & 1; 或 set_col = ‘val1,val2′
11. mysql> SHOW WARNINGS;
12. 在将一个字符串列同一个数字进行比较时, MySQL 不能使用列中的索引进行快速查找
13. <=> (NULL-safe equal).若有一个或两个参数为 NULL,除非NULL-safe <=> 等算符,则比较运算的结果为NULL。
14. expr BETWEEN min AND max 相当于 min <= expr AND expr <= max
15. CASE value WHEN [compare-value] THEN result [WHEN [compare-value] THEN result ...] [ELSE result] END CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END
CASE .. WHEN .. THEN .. ELSE .. END
16. IF(expr1,expr2,expr3)
17. IFNULL(expr1,expr2)
18. NULLIF(expr1,expr2)
19. CHAR_LENGTH(str) 多字节也按一个字算
20. LENGTH(str)
21. CONCAT(str1,str2,...) CONCAT_WS(separator,str1,str2,...)
22. FIELD(str,str1,str2,str3,...)
23. FIND_IN_SET(str,strlist)
24. FORMAT(X,D) 将number X设置为格式 '#,###,###.##', 以四舍五入的方式保留到小数点后D位,
25. LOWER() UPPER()
26. LEFT(str,len) RIGHT(str,len)
27. REPLACE(str,from_str,to_str)
28. SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
29. expr LIKE pat [ESCAPE 'escape-char']
30. expr REGEXP pat expr RLIKE pat
31. ABS(X)
CEIL(X)
FLOOR(X)
ROUND(X) ROUND(X,D)
MOD(N,M)
TRUNCATE(X,D)
RAND() RAND(N)
若要在i ≤ R ≤ j 这个范围得到一个随机整数R ,需要用到表达式 FLOOR(i + RAND() * (j – i + 1))。
32. MICROSECOND(expr)
33. NOW() NOW()+0
34. EXPLAIN
35. 全文搜索功能
1. MATCH (col1,col2,...) AGAINST (expr [IN BOOLEAN MODE | WITH QUERY EXPANSION])
2. 布尔全文搜索
mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST (‘+MySQL -YourSQL’ IN BOOLEAN MODE);
它们不使用 50% 域值。
它们不会按照相关性渐弱的顺序将行进行分类。
停止字适用
可用操作符:+ – > < () ~ * "
3. 全文搜索带查询扩展
内隐知识: 搜database 时 ,mysql ,oracle等均为符合database的项
mysql> SELECT * FROM articles
-> WHERE MATCH (title,body)
-> AGAINST (‘database’ WITH QUERY EXPANSION);
全文限定条件:
全文搜索只适用于 MyISAM 表。
全文搜索可以同大多数多字节字符集一起使用。Unicode属于例外情况; 可使用utf8 字符集 , 而非ucs2字符集。
诸如汉语和日语这样的表意语言没有自定界符。因此, FULLTEXT分析程序不能确定在这些或其它的这类语言中词的起始和结束的位置。
MATCH()列列表必须同该表中一些 FULLTEXT索引定义中的列列表完全符合,除非MATCH()在IN BOOLEAN MODE。
对AGAINST() 的参数必须是一个常数字符串。
36. CAST(expr AS type)
37. 加密函数
a) 你想要储存一些由可能包含任意字节值的加密函数返回的结果,使用BLOB列而不是 CHAR 或VARCHAR 列,从而避免由于结尾空格的删除而改变一些数据值的潜在问题。
b) AES_ENCRYPT(str,key_str) , AES_DECRYPT(crypt_str,key_str)
c) ENCODE(str,pass_str) DECODE(crypt_str,pass_str)
38. FOUND_ROWS()
mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
-> WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();
39. ROW_COUNT()返回被前面语句升级的、插入的或删除的行数。
40. LAST_INSERT_ID() LAST_INSERT_ID(expr)
41. VERSION()
42. INET_ATON(expr) INET_NTOA(expr)
43. VALUES(col_name) VALUES()函数只在INSERT … UPDATE 语句中有意义
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
44. GROUP BY(聚合)函数
a) AVG([DISTINCT] expr)
返回expr 的平均值。 DISTINCT 选项可用于返回 expr的不同值的平均值。
b) COUNT(expr) COUNT(DISTINCT expr,[expr...])
c) GROUP_CONCAT([DISTINCT] expr [,expr ...] [ORDER BY {unsigned_integer | col_name | expr} [ASC | DESC] [,col_name ...]] [SEPARATOR str_val])
mysql> SELECT student_name, GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ‘ ‘) FROM student GROUP BY student_name;
d) MIN([DISTINCT] expr), MAX([DISTINCT] expr)
e) WITH ROLLUP
mysql> SELECT year, SUM(profit) FROM sales GROUP BY year WITH ROLLUP;
当你使用 ROLLUP时, 你不能同时使用 ORDER BY子句进行结果排序,换言之, ROLLUP 和ORDER BY 是互相排斥的。
45. 数据库定义语句:
a) ALTER DATABASE
b) ALTER TABLE
c) CREATE DATABASE
d) CREATE INDEX
对于CHAR和VARCHAR列,只用一列的一部分就可创建索引。创建索引时,使用col_name(length)语法,对前缀编制索引。前缀包括每列值的前length个字符。BLOB和TEXT列也可以编制索引,但是必须给出前缀长度。
CREATE INDEX part_of_name ON customer (name(10));
e) CREATE TABLE
f) DROP DATABASE
g) DROP INDEX
h) DROP TABLE
i) RENAME TABLE
数据库操作语句:
a) DELETE
b) DO
c) HANDLER
d) INSERT
a) DELAYED
b) IGNORE
c) ON DUPLICATE KEY UPDATE
d) INSERT … SELECT
e) LOAD DATA INFILE
f) REPLACE
除非表有一个PRIMARY KEY或UNIQUE索引,否则,使用一个REPLACE语句没有意义。
g) SELECT
a) JOIN
b) UNION , UNION ALL
1.列于每个SELECT语句的对应位置的被选择的列应具有相同的类型。在第一个SELECT语句中被使用的列名称也被用于结果的列名称。
2.如果您对UNION不使用关键词ALL,则所有返回的行都是唯一的,如同您已经对整个结果集合使用了DISTINCT。如果您指定了ALL,您会从所有用过的SELECT语句中得到所有匹配的行。
3.如果您想使用ORDER BY或LIMIT子句来对全部UNION结果进行分类或限制,则应对单个地SELECT语句加圆括号,并把ORDER BY或LIMIT放到最后一个的后面。
4.mysql->
(SELECT a FROM tbl_name WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM tbl_name WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
圆括号中用于单个SELECT语句的ORDER BY只有当与LIMIT结合后,才起作用。否则,ORDER BY被优化去除。
c) SELECT…INTO OUTFILE
一个HAVING子句必须位于GROUP BY子句之后,并位于ORDER BY子句之前。
查找id在tb1里有tb2里没有的:mysql> SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id WHERE table2.id IS NULL;
d) USE INDEX(key_list),IGNORE INDEX(key_list)FORCE INDEX
USE KEY、IGNORE KEY和FORCE KEY是USE INDEX、IGNORE INDEX和FORCE INDEX的同义词
h) Subquery 子查询
IN : IN是=ANY的别名 NOT IN是<> ALL的别名
ANY: 对于在子查询返回的列中的任一数值,如果比较结果为TRUE的话,则返回TRUE
SOME: 词语SOME是ANY的别名
ALL: 对于子查询返回的列中的所有值,如果比较结果为TRUE,则返回TRUE。
行子查询:
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
EXISTS, NOT EXISTS
i) TRUNCATE
j) UPDATE
46. MySQL实用工具语句
a) {DESCRIBE | DESC} tbl_name [col_name | wild] 它是SHOW COLUMNS FROM的快捷方式. SHOW CREATE TABLE和SHOW TABLE STATUS语句也可以提供有关表的信息
b) MySQL事务处理和锁定语句
c)
47. SHOW INDEX FROM `uchome_yk_shop` , 查看表所有用的索引. 另有空看看:MySQL Query Profiler
48. query_cache_type (query search)
49. 在语句后加上\G可以坚排显示
50. 存储程序
a) CREATE PROCEDURE ; CREATE FUNCTION
b) DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
c) SHOW CREATE {PROCEDURE | FUNCTION} sp_name
d) SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS
e) CALL sp_name([parameter[,...]])
f) BEGIN … END 中间里语句必需用;结尾
g) DECLARE , DECLARE仅被用在BEGIN … END复合语句里,并且必须在复合语句的开头,在任何其它语句之前。
DECLARE var_name[,...] type [DEFAULT value] 设置局部变量
DECLARE condition_name CONDITION FOR condition_value DECLARE条件
DECLARE cursor_name CURSOR FOR select_statement 声明光标
h) SELECT … INTO语句 把列存储到变量,因此,只有单一的行可以被取回。
SELECT col_name[,...] INTO var_name[,...] table_expr
例:SELECT id,data INTO x,y FROM test.t1 LIMIT 1;
i) DELIMITER // 把;换成//
51. 触发程序
a) CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt
b) DROP TRIGGER [schema_name.]trigger_name
c) OLD和NEW是对触发程序的MySQL扩展
52. 视图
a) CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
b) mysql> CREATE VIEW test.v AS SELECT * FROM t;
c) WITH CHECK OPTION子句来防止插入或更新行
d) DROP VIEW [IF EXISTS] view_name [, view_name] … [RESTRICT | CASCADE]
e) SHOW CREATE VIEW
53. 事务
54. 优化
a) MySQL能更高效地在声明具有相同类型和尺寸的列上使用索引
b) ANALYZE TABLE ;告诉MySQL分析关键字分布
c) 要想使一个较慢速SELECT … WHERE更快,应首先检查是否能增加一个索引。不同表之间的引用通常通过索引来完成。
d) 索引使用的常数表达式仅计算一次。
e) MySQL怎样优化WHERE子句
i. 对于MyISAM和HEAP表,在一个单个表上的没有一个WHERE的COUNT(*)直接从表中检索信息。当仅使用一个表时,对NOT NULL表达式也这样做。
ii. 如果不使用GROUP BY或分组函数(COUNT()、MIN()……),HAVING与WHERE合并。
iii. 对于联接内的每个表,构造一个更简单的WHERE以便更快地对表进行WHERE计算并且也尽快跳过记录。
所有常数的表在查询中比其它表先读出。常数表为:空表或只有1行的表。
与在一个PRIMARY KEY或UNIQUE索引的WHERE子句一起使用的表,这里所有的索引部分使用常数表达式并且索引部分被定义为NOT NULL.
f) 范围优化
g) …
h) 其它优化技巧
i. 对于频繁更改的MyISAM表,应试图避免所有变长列(VARCHAR、BLOB和TEXT)。如果表包括单一的变长列则使用动态记录格式。
i) 优化数据库结构
i. 尽可能地使用最有效(最小)的数据类型
ii. 尽可能使用较小的整数类型使表更小。例如,MEDIUMINT经常比INT好一些,因为MEDIUMINT列使用的空间要少25%。
iii. 如果可能,声明列为NOT NULL。它使任何事情更快而且每列可以节省一位。注意如果在应用程序中确实需要NULL,应该毫无疑问使用它,只是避免 默认地在所有列上有它。

让IE6支持position:fixed

1.body,里的背景图片 fixed,这里一定要有,就算写个不存在的图片。

body {background:url(foo) fixed;}

2.要fixed的元素absolute;

#header{
    position:absolute;
}

3.样式表达式

top:expression(
      eval(document.compatMode && document.compatMode=='CSS1Compat')
      ? documentElement.scrollTop
     : document.body.scrollTop)

这段样式可以在单独的ie.css,只在IE6及更底版本中加载

<!--[if lt IE 7]>
   <link rel="stylesheet" href="ie.css" type="text/css">
<![endif]-->

IE7,IE8中flash调用不了JS的问题

在IE7,IE8中,以下HTML中嵌入的flash在执行ExternalInterface.addCallback时会报JS错:

<object height=”400″ width=”300″> … embed code here … </object>

解决的方案是给这个object增加一个任意ID

<object height=”400″ width=”300″ id="objid" > … embed code here … </object>

如果再优美一点可以在AS3中这样写

if(ExternalInterface.available&&ExternalInterface.objectID!=null)
{
    ExternalInterface.addCallback(”myFunc”,_myFunc);
}

AJAX前进后退及书签

ajax前后退功能原理其实比较简单,改变hash值促使浏览器激活前后退按钮。
在IE8以下的浏览器不支持js修改hash,遂增加额外的隐藏iframe,通过修改其src来达到同样的目的。
知道原理后,我们可以很快把它实现。下面介绍一个Jquery插件和一个库RSH

(function($) {
    var locationWrapper = {
        put: function(hash, win) {
            (win || window).location.hash = encodeURIComponent(hash);
        },
        get: function(win) {
            var hash = ((win || window).location.hash).replace(/^#/, '');
            return $.browser.mozilla ? hash : decodeURIComponent(hash);
        }
    };

    var iframeWrapper = {
        id: "__jQuery_history",
        init: function() {
            var html = '<iframe id="'+ this.id +'" style="display:none" src="javascript:false;" />';
            $("body").prepend(html);
            return this;
        },
        _document: function() {
            return $("#"+ this.id)[0].contentWindow.document;
        },
        put: function(hash) {
            var doc = this._document();
            doc.open();
            doc.close();
            locationWrapper.put(hash, doc);
        },
        get: function() {
            return locationWrapper.get(this._document());
        }
    };

    // public base interface
    var _ = {
        appState: undefined,
        callback: undefined,
        init:  function(callback) {},
        check: function() {},
        load:  function(hash) {}
    };
    $.history = _;

    var SimpleImpl = {
        init: function(callback) {
            _.callback = callback;
            var current_hash = locationWrapper.get();
            _.appState = current_hash;
            _.callback(current_hash);
            setInterval(_.check, 100);
        },
        check: function() {
            var current_hash = locationWrapper.get();
            if(current_hash != _.appState) {
                _.appState = current_hash;
                _.callback(current_hash);
            }
        },
        load: function(hash) {
            if(hash != _.appState) {
                locationWrapper.put(hash);
                _.appState = hash;
                _.callback(hash);
            }
        }
    };

    var IframeImpl = {
        init: function(callback) {
            _.callback = callback;
            var current_hash = locationWrapper.get();
            _.appState = current_hash;
            iframeWrapper.init().put(current_hash);
            _.callback(current_hash);
            setInterval(_.check, 100);
        },
        check: function() {
            var current_hash = iframeWrapper.get();
            if(current_hash != _.appState) {
                locationWrapper.put(current_hash);
                _.appState = current_hash;
                _.callback(current_hash);
            }
        },
        load: function(hash) {
            if(hash != _.appState) {
                locationWrapper.put(hash);
                iframeWrapper.put(hash);
                _.appState = hash;
                _.callback(hash);
            }
        }
    };

    if($.browser.msie && ($.browser.version < 8 || document.documentMode < 8)) {
        $.extend(_, IframeImpl);
    } else {
        $.extend(_, SimpleImpl);
    }
})(jQuery);

关于RSH,由于他的代码比较多,就不贴出来了,想看源码的可以点击这里下载。RSH对各种浏览器都做了相应的处理,如safari,opara。而且它用隐藏的表单存储hash对应的数据,很方便的缓存数据,在实际运用中前进后退,就不用重新发送ajax去请求数据了。PS:搜狐白社会ajax后退功能好像就用的这个库,掐指算的:)

Zend Framework 多模块模型自动加载(models auto-loading)

众所周知,ZF是一个MVC的PHP框架,而且它能很方便的部署多模块程序。如:

ZF多模块

ZF多模块

但这样做会遇到一个问题:模块里怎么加载 models/ 下的 模型类。

现有如下解决方案:

1.把所有模块下的models写进include_path,实现自动加载。

2.把所有模型类放在library下,和Zend库同级,也能实现自动加载。

3.每次在controller里手动包含所用类的路径

除此之外,有位山人出此妙招:

<?php
abstract class System_Controller_Action extends Zend_Controller_Action
{
    //加载Model
    public function loadModel($class, $module = null)
    {
        $modelDir = $this->getFrontController()->getModuleDirectory($module)
                       . DIRECTORY_SEPARATOR . 'models';
        Zend_Loader::loadClass($class, $modelDir);

        return $class;
    }

}