Elton's Blog

Database

MySQL Query Cache

by Elton on 2010年07月5日, under Database

顾名思义,MySQL Query Cache 就是用来缓存和 Query 相关的数据的。具体来说,Query Cache 缓存了我们客户端提交给 MySQL 的 SELECT 语句以及该语句的结果集。大概来讲,就是将 SELECT 语句和语句的结果做了一个 HASH 映射关系然后保存在一定的内存区域中。

在大部分的 MySQL 分发版本中,Query Cache 功能默认都是打开的,我们可以通过调整 MySQL Server 的参数选项打开该功能。主要由以下5个参数构成:

query_cache_limit:允许 Cache 的单条 Query 结果集的最大容量,默认是1MB,超过此参数设置的 Query 结果集将不会被 Cache
query_cache_min_res_unit:设置 Query Cache 中每次分配内存的最小空间大小,也就是每个 Query 的 Cache 最小占用的内存空间大小
query_cache_size:设置 Query Cache 所使用的内存大小,默认值为0,大小必须是1024的整数倍,如果不是整数倍,MySQL 会自动调整降低最小量以达到1024的倍数
query_cache_type:控制 Query Cache 功能的开关,可以设置为0(OFF),1(ON)和2(DEMAND)三种,意义分别如下:
0(OFF):关闭 Query Cache 功能,任何情况下都不会使用 Query Cache
1(ON):开启 Query Cache 功能,但是当 SELECT 语句中使用的 SQL_NO_CACHE 提示后,将不使用Query Cache
2(DEMAND):开启 Query Cache 功能,但是只有当 SELECT 语句中使用了 SQL_CACHE 提示后,才使用 Query Cache
query_cache_wlock_invalidate:控制当有写锁定发生在表上的时刻是否先失效该表相关的 Query Cache,如果设置为 1(TRUE),则在写锁定的同时将失效该表相关的所有 Query Cache,如果设置为0(FALSE)则在锁定时刻仍然允许读取该表相关的 Query Cache。
Query Cache 如何处理子查询的?
这是我遇到的最为常见的一个问题。其实 Query Cache 是以客户端请求提交的 Query 为对象来处理的,只要客户端请求的是一个 Query,无论这个 Query 是一个简单的单表查询还是多表 Join,亦或者是带有子查询的复杂 SQL,都被当作成一个 Query,不会被分拆成多个 Query 来进行 Cache。所以,存在子查询的复杂 Query 也只会产生一个Cache对象,子查询不会产生单独的Cache内容。UNION[ALL] 类型的语句也同样如此。

Query Cache 是以 block 的方式存储的数据块吗?
不是,Query Cache 中缓存的内容仅仅只包含该 Query 所需要的结果数据,是结果集。当然,并不仅仅只是结果数据,还包含与该结果相关的其他信息,比如产生该 Cache 的客户端连接的字符集,数据的字符集,客户端连接的 Default Database等。

Query Cache 为什么效率会非常高,即使所有数据都可以 Cache 进内存的情况下,有些时候也不如使用 Query Cache 的效率高?
Query Cache 的查找,是在 MySQL 接受到客户端请求后在对 Query 进行权限验证之后,SQL 解析之前。也就是说,当 MySQL 接受到客户端的SQL后,仅仅只需要对其进行相应的权限验证后就会通过 Query Cache 来查找结果,甚至都不需要经过 Optimizer 模块进行执行计划的分析优化,更不许要发生任何存储引擎的交互,减少了大量的磁盘 IO 和 CPU 运算,所以效率非常高。

客户端提交的 SQL 语句大小写对 Query Cache 有影响吗?
有,由于 Query Cache 在内存中是以 HASH 结构来进行映射,HASH 算法基础就是组成 SQL 语句的字符,所以必须要整个 SQL 语句在字符级别完全一致,才能在 Query Cache 中命中,即使多一个空格也不行。

一个 SQL 语句在 Query Cache 中的内容,在什么情况下会失效?
为了保证 Query Cache 中的内容与是实际数据绝对一致,当表中的数据有任何变化,包括新增,修改,删除等,都会使所有引用到该表的 SQL 的 Query Cache 失效。

为什么我的系统在开启了 Query Cache 之后整体性能反而下降了?
当开启了 Query Cache 之后,尤其是当我们的 query_cache_type 参数设置为 1 以后,MySQL 会对每个 SELECT 语句都进行 Query Cache 查找,查找操作虽然比较简单,但仍然也是要消耗一些 CPU 运算资源的。而由于 Query Cache 的失效机制的特性,可能由于表上的数据变化比较频繁,大量的 Query Cache 频繁的被失效,所以 Query Cache 的命中率就可能比较低下。所以有些场景下,Query Cache 不仅不能提高效率,反而可能造成负面影响。

如何确认一个系统的 Query Cache 的运行是否健康,命中率如何,设置量是否足够?
MySQL 提供了一系列的 Global Status 来记录 Query Cache 的当前状态,具体如下:

Qcache_free_blocks:目前还处于空闲状态的 Query Cache 中内存 Block 数目
Qcache_free_memory:目前还处于空闲状态的 Query Cache 内存总量
Qcache_hits:Query Cache 命中次数
Qcache_inserts:向 Query Cache 中插入新的 Query Cache 的次数,也就是没有命中的次数
Qcache_lowmem_prunes:当 Query Cache 内存容量不够,需要从中删除老的 Query Cache 以给新的 Cache 对象使用的次数
Qcache_not_cached:没有被 Cache 的 SQL 数,包括无法被 Cache 的 SQL 以及由于 query_cache_type 设置的不会被 Cache 的 SQL
Qcache_queries_in_cache:目前在 Query Cache 中的 SQL 数量
Qcache_total_blocks:Query Cache 中总的 Block 数量
可以根据这几个状态计算出 Cache 命中率,计算出 Query Cache 大小设置是否足够,总的来说,我个人不建议将 Query Cache 的大小设置超过256MB,这也是业界比较常用的做法。

MySQL Cluster 是否可以使用 Query Cache?
其实在我们的生产环境中也没有使用 MySQL Cluster,所以我也没有在 MySQL Cluster 环境中使用 Query Cache 的实际经验,只是 MySQL 文档中说明确实可以在 MySQL Cluster 中使用 Query Cache。从 MySQL Cluster 的原理来分析,也觉得应该可以使用,毕竟 SQL 节点和数据节点比较独立,各司其职,只是 Cache 的失效机制会要稍微复杂一点。

引自:http://www.javaeye.com/news/16744-mysql-query-cache-summary

2 Comments :, , more...

Oracle导入数据

by Elton on 2010年01月16日, under Database

导入sql表结构

• 用sqlplus命令登录Oracle

  1.  
  2. sqlplus system/password@orcl
  3.  

• 使用@命令导入sql文件

  1.  
  2. SQL> @/path/to/file/sample.sql
  3.  

2. 导入数据
• 导入ctl文件
在命令行中,执行

  1.  
  2. sqlldr userid=username/password control=sample.ctl
  3.  
Leave a Comment :, , more...

Oracle数据库列出所有表

by Elton on 2010年01月10日, under Database

可以使用下面的命令来列出当前用户所有的表

  1.  
  2. SELECT * FROM tab;
  3. SELECT table_name FROM user_tables;
  4.  

如果想列出所有的表,可以使用

  1.  
  2. SELECT table_name FROM all_tables;
  3.  
Leave a Comment :, more...

Oracle数据库建立表空间、用户以及授权

by Elton on 2010年01月10日, under Database

• 用system用户登录。system用户默认就有DBA的权限

  1.  
  2. sqlplus system/password@orcl
  3.  

• 查看数据文件存放位置

  1.  
  2. SELECT file_name FROM dba_data_files;
  3.  
  4. FILE_NAME
  5. ——————————————————————————–
  6. /Users/oracle/oradata/orcl/users01.dbf
  7. /Users/oracle/oradata/orcl/sysaux01.dbf
  8. /Users/oracle/oradata/orcl/undotbs01.dbf
  9. /Users/oracle/oradata/orcl/system01.dbf
  10. /Users/oracle/oradata/orcl/example01.dbf
  11.  

• 建立临时表空间

  1.  
  2. CREATE TEMPORARY tablespace decernis_temp
  3. tempfile ‘/Users/oracle/oradata/orcl/decernis_temp01.dbf’
  4. size 32m
  5. autoextend ON
  6. next 32m maxsize 2048m
  7. extent management LOCAL;
  8.  
  9. Tablespace created.
  10.  

• 建立用户数据表空间

  1.  
  2. CREATE tablespace decernis_data
  3. logging
  4. datafile ‘/Users/oracle/oradata/orcl/decernis_data01.dbf’
  5. size 32m
  6. autoextend ON
  7. next 32m maxsize 2048m
  8. extent management LOCAL;
  9.  
  10. Tablespace created.
  11.  

• 创建用户

  1.  
  2. CREATE user decernis IDENTIFIED BY password
  3. DEFAULT tablespace decernis_data
  4. TEMPORARY tablespace decernis_temp;
  5.  

• 授予权限

  1.  
  2. GRANT dba,connect,resource TO decernis;
  3.  

注意,上面语句中,制定数据文件路径的时候,一定要使用单引号,否则会出现“ORA-00972: identifier is too long”的错误。

如果最后一行不添加,则用户没有表空间分配EXTENT的权限,将会会出现“ORA-01950: no privileges on tablespace
”的错误。

以后,这个用户所操作的表,就自动分配到这个表空间了。

1 Comment :, , , , , , more...

针对SQLite3为Cocoa 和 Cocoa Touch设计的持久化对象

by Elton on 2009年10月26日, under Database, Mac

向大家推荐一款很不错的轻量级的Cocoa持久化对象 — sqlitepersistentobjects

使用起来跟ActiveRecord很类似,也非常简单
将下载的zip中的所有文件加入你的项目中,然后链接libsqlite3.dylib,之后你就可以声明实体类了。

  1.  
  2. #import <foundation/foundation.h>
  3. #import "SQLitePersistentObject.h"
  4.  
  5. @interface PersistablePerson : SQLitePersistentObject {
  6.  NSString *lastName;
  7.  NSString *firstName;
  8. }
  9. @property (nonatomic, retain) NSString * lastName;
  10. @property (nonatomic, retain) NSString * firstName;
  11. @end
  12.  

然后你可以这样使用它:

  1.  
  2. PersistablePerson *person = [[PersistablePerson alloc] init];
  3. person.firstName = @"Joe";
  4. person.lastName = @"Smith";
  5.  

当你打算保存的时候:

  1.  
  2. [person save];
  3.  

是不是很简单

Leave a Comment :, more...

SQLite3 简要使用指南

by Elton on 2009年10月26日, under Database

OS X自从10.4后把SQLite这套相当出名的数据库软件,放进了作业系统工具集里。OS X包装的是第三版的SQLite,又称SQLite3。这套软件有几个特色:

  • 支援大多数的SQL指令(下面会简单介绍)。
  • 一个档案就是一个数据库。不需要安装数据库服务器软件。
  • 完整的Unicode支援(因此没有跨语系的问题)。
  • 速度很快。

目前在OS X 10.4里,SQLite是以/usr/bin/sqlite3的形式包装,也就说这是一个命令列工具,必须先从终端机(Terminal.app或其他程序)进入shell之后才能使用。网络上有一些息协助使用SQLite的视觉化工具,但似乎都没有像CocoaMySQL(配合MySQL数据库使用)那般好用。或许随时有惊喜也未可知,以下仅介绍命令列的操作方式。

以下我们就建立数据库、建立资料表及索引、新增资料、查询资料、更改资料、移除资料、sqlite3命令列选项等几个项目做简单的介绍。

建立数据库档案

用sqlite3建立数据库的方法很简单,只要在shell下键入(以下$符号为shell提示号,请勿键入):

  1.  
  2. $ sqlite3 foo.db
  3.  

如果目录下没有foo.db,sqlite3就会建立这个数据库。sqlite3并没有强制数据库档名要怎么取。

在sqlite3提示列下操作

进入了sqlite3之后,会看到以下文字:

  1.  
  2. SQLite version 3.1.3
  3. Enter ".help" for instructions
  4. sqlite>
  5.  

这时如果使用.help可以取得求助,.quit则是离开(请注意:不是quit)

SQL的指令格式

所以的SQL指令都是以分号(;)结尾的。如果遇到两个减号(–)则代表注解,sqlite3会略过去。

建立资料表

假设我们要建一个名叫film的资料表,只要键入以下指令就可以了:

  1.  
  2. CREATE TABLE film(title, length, year, starring);
  3.  

这样我们就建立了一个名叫film的资料表,里面有name、length、year、starring四个字段。

这个create table指令的语法为:

  1.  
  2. CREATE TABLE table_name(field1, field2, field3, …);
  3.  

table_name是资料表的名称,fieldx则是字段的名字。sqlite3与许多SQL数据库软件不同的是,它不在乎字段属于哪一种资料型态:sqlite3的字段可以储存任何东西:文字、数字、大量文字(blub),它会在适时自动转换。

建立索引

如果资料表有相当多的资料,我们便会建立索引来加快速度。好比说:

  1.  
  2. CREATE INDEX film_title_index ON film(title);
  3.  

意思是针对film资料表的name字段,建立一个名叫film_name_index的索引。这个指令的语法为

  1.  
  2. CREATE INDEX index_name ON table_name(field_to_be_indexed);
  3.  

一旦建立了索引,sqlite3会在针对该字段作查询时,自动使用该索引。这一切的操作都是在幕后自动发生的,无须使用者特别指令。

加入一笔资料

接下来我们要加入资料了,加入的方法为使用insert into指令,语法为:

  1.  
  2. INSERT INTO table_name VALUES(data1, data2, data3, …);
  3.  

例如我们可以加入

  1.  
  2. INSERT INTO film VALUES (‘Silence of the Lambs, The’, 118, 1991, ‘Jodie Foster’);
  3. INSERT INTO film VALUES (‘Contact’, 153, 1997, ‘Jodie Foster’);
  4. INSERT INTO film VALUES (‘Crouching Tiger, Hidden Dragon’, 120, 2000, ‘Yun-Fat Chow’);
  5. INSERT INTO film VALUES (‘Hours, The’, 114, 2002, ‘Nicole Kidman’);
  6.  

如果该字段没有资料,我们可以填NULL。

查询资料

讲到这里,我们终于要开始介绍SQL最强大的select指令了。我们首先简单介绍select的基本句型:

  1.  
  2. SELECT COLUMNS FROM table_name WHERE expression;
  3.  

最常见的用法,当然是倒出所有数据库的内容:

  1.  
  2. SELECT * FROM film;
  3.  

如果资料太多了,我们或许会想限制笔数:

  1.  
  2. SELECT * FROM film LIMIT 10;
  3.  

或是照着电影年份来排列:

  1.  
  2. SELECT * FROM film ORDER BY year LIMIT 10;
  3.  

或是年份比较近的电影先列出来:

  1.  
  2. SELECT * FROM film ORDER BY year DESC LIMIT 10;
  3.  

或是我们只想看电影名称跟年份:

  1.  
  2. SELECT title, year FROM film ORDER BY year DESC LIMIT 10;
  3.  

查所有茱蒂佛斯特演过的电影:

  1.  
  2. SELECT * FROM film WHERE starring=‘Jodie Foster’;
  3.  

查所有演员名字开头叫茱蒂的电影(‘%’ 符号便是 SQL 的万用字符):

  1.  
  2. SELECT * FROM film WHERE starring LIKE ‘Jodie%’;
  3.  

查所有演员名字以茱蒂开头、年份晚于1985年、年份晚的优先列出、最多十笔,只列出电影名称和年份:

  1.  
  2. SELECT title, year FROM film WHERE starring LIKE ‘Jodie%’ AND year >= 1985 ORDER BY year DESC LIMIT 10;
  3.  

有时候我们只想知道数据库一共有多少笔资料:

  1.  
  2. SELECT count(*) FROM film;
  3.  

有时候我们只想知道1985年以后的电影有几部:

  1.  
  2. SELECT count(*) FROM film WHERE year >= 1985;
  3.  

(进一步的各种组合,要去看SQL专书,不过你大概已经知道SQL为什么这么流行了:这种语言允许你将各种查询条件组合在一起──而我们还没提到「跨数据库的联合查询」呢!)

如何更改或删除资料

了解select的用法非常重要,因为要在sqlite更改或删除一笔资料,也是靠同样的语法。

例如有一笔资料的名字打错了:

  1.  
  2. UPDATE film SET starring=‘Jodie Foster’ WHERE starring=‘Jodee Foster’;
  3.  

就会把主角字段里,被打成’Jodee Foster’的那笔(或多笔)资料,改回成Jodie Foster。

  1.  
  2. DELETE FROM film WHERE year < 1970;
  3.  

就会删除所有年代早于1970年(不含)的电影了。

其他sqlite的特别用法

sqlite可以在shell底下直接执行命令:

  1.  
  2. sqlite3 film.db "select * from film;"
  3.  

输出 HTML 表格:

  1.  
  2. sqlite3 -html film.db "select * from film;"
  3.  

将数据库「倒出来」:

  1.  
  2. sqlite3 film.db ".dump" > output.sql
  3.  

利用输出的资料,建立一个一模一样的数据库(加上以上指令,就是标准的SQL数据库备份了):

  1.  
  2. sqlite3 film.db < output.sql
  3.  

在大量插入资料时,你可能会需要先打这个指令:

  1.  
  2. begin;
  3.  

插入完资料后要记得打这个指令,资料才会写进数据库中:

  1.  
  2. commit;
  3.  

小结

以上我们介绍了SQLite这套数据库系统的用法。事实上OS X也有诸于SQLiteManagerX这类的图形接口程序,可以便利数据库的操作。不过万变不离其宗,了解SQL指令操作,SQLite与其各家变种就很容易上手了。

至于为什么要写这篇教学呢?除了因为OS X Tiger大量使用SQLite之外(例如:Safari的RSS reader,就是把文章存在SQLite数据库里!你可以开开看~/Library/Syndication/Database3这个档案,看看里面有什么料),OpenVanilla从0.7.2开始,也引进了以SQLite为基础的词汇管理工具,以及全字库的注音输入法。因为使用SQLite,这两个模块不管数据库内有多少笔资料,都可以做到「瞬间启动」以及相当快速的查询回应。

将一套方便好用的数据库软件包进OS X中,当然也算是Apple相当相当聪明的选择。再勤劳一点的朋友也许已经开始想拿SQLite来记录各种东西(像我们其中就有一人写了个程序,自动记录电池状态,写进SQLite数据库中再做统计……)了。想像空间可说相当宽广。

目前支援SQLite的程序语言,你能想到的大概都有了。这套数据库2005年还赢得了美国O’Reilly Open Source Conference的最佳开放源代码软件奖,奖评是「有什么东西能让Perl, Python, PHP, Ruby语言团结一致地支援的?就是SQLite」。由此可见SQLite的地位了。而SQLite程序非常小,更是少数打 “gcc -o sqlite3 *”,不需任何特殊设定就能跨平台编译的程序。小而省,小而美,SQLite连网站都不多赘言,直指SQL语法精要及API使用方法,原作者大概也可以算是某种程序设计之道(Tao of Programming)里所说的至人了。

Leave a Comment : more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit my friends!

A few highly recommended friends...