Oracle DBA学习笔记

数据库、安装等

初始化参数

  • MAX_ENABLED_ROLES:用户拥有的有效角色的最大值
  • DB_CACHE_SIZE:数据库缓存大小

建立数据库

建立数据库之前需要考虑以下条件。

  • 拥有SYSDBA权限
  • 若使用操作系统认证,则需要建立相关操作系统帐户, 若使用密码文件认证,则需要建立密码文件
  • 足够的内存
  • 足够的磁盘空间

建立数据库时执行的脚本:

sql.bsq建立数据字典的表建立数据库时由Oracle自动执行
catalog.sql建立数据字典视图建立数据库之后由管理者手动执行

数据库模板

  • 仅包括数据库结构的模板
    • 表空间
    • 数据文件
    • 初始化参数
  • 包括数据库结构和用户数据的模板
    • 表空间
    • 数据文件
    • 初始化参数
    • 用户schema
    • 用户数据

OFA

Optimal Flexible Architecture,Oracle推荐的目录结构, 将数据文件、控制文件、日志等分散在多个磁盘中。好处:

  • 能轻易地区分数据文件和系统文件
  • 可以简单地识别控制文件、数据文件、日志等
  • 同一台服务器上建立多个Oracle数据库时降低管理难度
  • 通过分散数据文件,减少读写文件时的冲突,提高性能

Oracle Universal Installer

启动之前需要建立拥有 Oracle 的系统帐户(oracle用户、dba组、oinstall组)

监察(audit)

使监察有效:设置初始化参数 AUDIT_TRAIL=DB OS NONE
  • DB: 监察记录写到 SYS.AUD$
  • OS: 监察记录写道操作系统日志中

控制文件

使用 CREATE CONTROLFILE 命令建立控制文件。

使用OMF(Oracle-Managed Files)管理文件时也能用CREATE CONTROLFILE命令建立控制文件, 但必须要指定 DATAFILE 和 LOGFILE。

可以过以下方法察看控制文件:

  • V$CONTROLFILES
  • V$PARAMETERS
  • show parameters 命令

控制文件在以下情况下更新。

数据文件和REDO日志文件的名称和位置数据库中添加、更改或删除数据文件和REDO日志文件时
表空间信息添加或删除表空间时
REDO日志的历史记录日志切换时
备份日志的位置和状态日志备份发生时
备份的位置和状态由Recovery Manager记录
现在的日志序号日志切换时
checkpoint信息checkpoint执行时

自动段(Segment)管理

  • 自动管理 PCTUSED、FREELISTS、FREELIST GROUPS参数
  • 提高空间利用率、提高并行数据插入的性能
  • 使用位图(而不是空闲列表)管理段内的空闲空间,插入数据时通过位图查找大小合适的数据块。
  • 不能保存LOB段和包含LOB列的表

段类型

  • 表(Table)
  • 分区表(Partition Table)
  • 簇(Cluster)
  • 索引(Index)
  • 索引组织表(Index-organized Table, IOT)
  • 分区索引(Partition Index)
  • UNDO段
  • 临时段:查询和建立索引时排序用
  • LOB
  • 嵌套表(Nested Table)
  • bootstrap:打开数据库时初始化数据字典时使用的段

其中UNDO段和临时段为系统建立,不属于 schema 对象。

rollback 段

包括系统rollback段非系统rollback段延迟rollback段三种。

  • 系统rollback段: 创建数据库时创建,仅当系统表空间内的对象发生变化时使用
  • 非系统rollback段: 自动管理、手动管理
  • 延迟rollback段: 事务进行时,表空间以 NORMAL 以外的方式脱机,事务信息将被保存在延迟rollback段中以便表空间联机时恢复事务。由oracle自动管理。

范围(extent)

范围(extent)管理

手动分配

ALTER TABME emp ALLOCATE EXTENT [(SIZE size DATAFILE 'filename)]

表空间

默认表空间

创建表时如果不指定表空间,则建立在schema规定的默认表领域中。

临时表空间

  • 创建:CREATE TEMPORARY TABLESPACE 语句,默认使用字典方式管理
  • 更改默认临时表空间:ALTER DATABSE DEFAULT TEMPORARY TABLESPACE 语句。

表空间管理

local表空间管理方式不能更改其存储参数(STORAGE)。 字典管理方式下可以更改存储参数。

Oracle9i中默认管理方式为local管理,8i 为字典管理。 9i中可以通过 EXTENT MANAGEMENT DICTIONARY 来指定字典管理方式。

使用 ALTER TABLESPACE user01 OFFLINE NORMAL 将表空间设置为OFFLINE的动作 会同时被记录到控制文件和数据字典中。

索引

索引

通过 ALTER INDEX … REBUILD 语句重新建立索引有以下特征:

  • 根据原有索引来建立新索引
  • 不需要排序
  • 建立时需要有足够的空间来容纳新旧索引。建立完毕后旧索引会被删除
  • 建立的索引中不包括已删除的数据
  • 建立过程中依然可以通过旧索引进行查询

监视索引

通过下面的方法来监视索引是否被使用。

ALTER INDEX ... MONITORING USAGE;

之后通过 V$OBJECT_USAGE 来确认索引的使用情况。例如

ALTER INDEX numb_oe_index MONITORING USAGE;     -- 监视开始
SELECT inde_name, usage FROM v$object_usage;    -- 确认使用情况
SELECT COUNT(*) FROM numbers WHERE odd_even='E';  -- 在numbers表上执行查询
SELECT inde_name, usage FROM v$object_usage;    -- 确认使用情况
ALTER SESSION SET optimizer_mode=first_rows;    -- 修改优化器为cost base
SELECT COUNT(*) FROM numbers WHERE odd_even='E';  -- 在numbers表上执行查询
SELECT inde_name, usage FROM v$object_usage;    -- 确认使用情况
ALTER INDEX numb_oe_index NOMONITORING USAGE;   -- 监视停止

临时表

临时表仅在当前会话或者当前事务中存在。 其生命期由 CREATE GLOBAL TEMPORARY TABLE语句的参数决定。

  • ON COMMIT DELETE ROWS:(默认)事务范围内存在
  • ON COMMIT PRESERVE ROWS:会话范围内存在

特性

  • 针对临时表的DML操作不锁定、不生成REDO日志
  • 可以针对临时表建立索引、视图、触发器。
  • 可以通过工具导入/导出其定义,但无法导出数据。

创建表时的注意事项

  • rollback segment、临时段、索引等放在不同的表空间,防止出现碎片
  • 尽可能少地分配 extent 以减少碎片
  • 尽量使用 local 管理以降低 overhead

表约束

约束延迟

创建约束时通过 [NOT] DEFERRABLE INITIALLY {IMMEDIATE|DEFERRED} 来设置延迟。 延迟即为事务提交时检查约束,反之则在语句执行时检查约束。

  • NOT DEFERRABLE 不能延迟
  • DEFERRABLE INITIALLY IMMEDIATE 能够延迟,但默认情况下为不延迟。DEFERRABLE 情况下的的默认设置
  • DEFERRABLE INITIALLY DEFERRABLE 能够延迟,默认情况下为延迟

修改延迟设置:

  • ALTER SESSION SET CONSTRANT[S] = {IMMEDIATE DEFERRED DEFAULT}
  • SET CONSTRANT[S] {constrant_name ALL} {IMMEDIATE DEFERRED}

一致性

读取一致性

默认情况下是语句级别读取一致性。 通过 SET TRANSACTION READ ONLY 可以使用事务级读写一致性。

日志(REDO Log)

checkpoint的发生条件

  • 日志切换
  • SHUTDOWN ABORT以外的方式终止实例
  • 由于FAST_START_MTTR_TARGET参数导致的强制执行
  • ALTER SYSTEM CHECKPOINT命令执行
  • OFFLINE NORMALREAD ONLYBEGIN BACKUP选项的 ALTER TABLESPACE命令

日志的archive

  • ARCHIVELOG模式:过去的日志文件被archive之后,才会被覆盖
  • ARCHIVELOG模式、NOARCHIVELOG模式:checkpoint结束之后过去的日志才会被覆盖

UNDO

建立

建立数据库时建立:

CREATE DATABASE ... UNDO TABLESPACE undo01 DATAFILE '...';

建立数据库之后建立:

CREATE UNDO TABLESPACE undo01 DATAFILE '...';

UNDO表空间管理

如果系统中有事务正在执行,那么切换UNDO表空间

ALTER SYSTEM SET undo_tablespace=undotbs2

会造成

  • 新的 UNDO 表空间中的 UNDO 段成为ONLINE状态
  • 旧 UNDO 表空间中包含事务的 UNDO 段成为 PENDING OFFLINE 状态

自动UNDO表空间管理的参数

UNDO_MANAGEMENTauto=自动管理 manual=手动管理
UNDO_TABLESPACE指定有效的undo表空间
UNDO_RETENTIONUNDO数据的保存时间(秒)
UNDO_SUPPRESS_ERRORS设置为true可以禁止显示 ORA_30019 错误信息

数据字典

数据字典

DBA_TAB_PRIVS对象权限
DBA_COL_PRIVS列权限
DBA_SYS_PRIVS系统权限
SESSION_PRIVS当前会话可以使用的系统权限
DBA_ROLLBACK_SEGS所有的rollback段的信息,但不包括OPTIMAL值
DBA_FREE_SPACES数据文件内可分配的连续空间的信息
DBA_USERS包含用户的角色信息

数据字典视图由 catalog.sql 脚本建立。

动态性能视图

使用动态性能视图可以获得以下信息。

V$DATAFILE数据文件
V$INSTANCE数据库状态
V$LOCK, V$LOCKED_OBJECT锁信息
V$SESSION会话信息
V$ROLLSTAT 有效rollback段的信息
V$ROLLNAME 仅包含rollback段id和名称,通常和V$ROLLSTAT结合使用

权限管理

用户

创建用户时使用 IDENTIFIED GLOBALLY AS ‘external’ 可以用企业目录服务(Enterprise Directory Service)进行用户认证。

操作系统认证

OS_AUTHENT_PREFIX参数值 + OS用户名 = Oracle用户名

角色

修改角色的条件:用户需要拥有 ALTER ANY ROLE 权限,或者以 WITH ADMIN OPTION 被赋予某个角色。

权限

DDL的系统权限在取消时不会连锁。例如 A -> B with admin option, B -> C,那么 A 在 revoke B 时 B 赋予 C 的权限不会被自动取消。

密码

  • PASSWORD_REUSE_TIME: 重复使用旧密码的最小间隔日数
  • PASSWORD_REUSE_MAX: 重复使用旧密码之前,最少需要修改几次密码
  • FAILED_LOGIN_ATTEMPTS: 密码错误超过规定次数以上则锁定帐户
  • PASSWORD_LOCK_TIME: 帐户锁定时间
  • PASSWORD_LIFE_TIME: 密码有效期限
  • PASSWORD_GRACE_TIME: 密码过期后多长时间内必须修改密码
  • PASSWORD_VERIFY_FUNCTION: 检查密码复杂度的函数

执行 utlpwdmg.sql 可以建立默认的复杂度检查函数。

策略(profile)

创建策略:

CREATE PROFILE dev_prof LIMIT
  IDLE_TIME 60
  SESSIONS_PER_USER 2
  CONNECT_TIME 30

创建策略时的参数:

CPU_PER_SESSION会话使用的CPU时间(单位0.01秒)
SESSIONS_PER_USER用户可以同时进行的会话数
CONNECT_TIME允许连接时间(分钟)
IDLE_TIME允许空闲时间(分钟)
LOGICAL_READS_PER_SESSION一次会话中能够进行的逻辑读次数(单位为数据块)
PRIVATE_SGA私有SGA的大小(单位为数据块)
CPU_PER_CALL一次调用(SQL语句)允许使用的CPU时间最大值(0.01秒)
LOGICAL_READS_PER_CALL一次调用(SQL语句)能够进行的逻辑读次数(单位为数据块)

如何使策略有效

  • 设置初始化参数 RESOURCE_LIMIT=TRUE
  • 用ALTER SYSTEM命令动态变更

SQL*Plus

确认表或视图的结构:

  • DESCRIBE 命令
  • DICT_COLUMNS 视图

(Read More)

有趣的乱码

今天客户发过来一个bug报告,说发送邮件时内容中书写はぁ~,收信时会显示成はち。 懂日文的朋友大概能明白,感叹词はぁ~怎么就变成了蜜蜂はち呢?

后来找到了原因。我们的邮件系统是用 Perl 写成的。其中有一个空格删除功能, 就是在显示时将邮件中的全角空格全部删除,其实现方法如下:

$body =~ s/ //g;

看起来似乎没有问题,但就是这条语句将はぁ~变成了はち。日文 euc-jp 编码下, 这几个字符串的编码如下:

| 字符串 | 编码 |h

はぁ~ A4CF A4A1 A1C1
はち A4CF A4C1
全角空格 A1A1

的后半个字符和的前半个字符恰好都是 A1,所以就被删除了,于是就出现了有意思的乱码现象。 修改方法也比较简单,只要正确识别出每个汉字的起止位置即可。

my $twoBytes   = '[\x8E\xA1-\xFE][\xA1-\xFE]';
my $threeBytes = '\x8F[\xA1-\xFE][\xA1-\xFE]';
while($body =~ s/\G(($twoBytes|$threeBytes|[\x00-\x7F])+?) /$1/g){};  # 识别汉字,如果汉字后面有空格则删除
$body =~ s/^ //g;        # 最后删除最开始处的全角空格

(Read More)

解决WordPress + mysql-5.0时的乱码问题

mysql 从版本 4.1 起增加了多国语言字符集功能。 数据在插入到数据库或者从数据库中取出时,mysql会自动进行字符集变换。 在创建数据库时必须要指定数据库字符编码,而客户端在连接mysql时也必须要指定客户端字符编码。 假设数据库字符编码utf8,而客户端字符编码gb2312, 那么执行select时mysql会将字符串从 utf8 转换成 gb2312, 而在执行 insert、update等时会将客户端输入的数据从 gb2312 转换成 utf8。

WordPress的数据使用 UTF-8 编码,因此在 mysql-5.0中创建数据库时应当将字符集指定为 utf8。 遗憾的是 php 等脚本语言不会自动设置客户端字符编码,因此mysql会选择默认的 latin1 , 这样在执行 select 时mysql会将数据从utf-8转换到latin1,造成乱码现象。

解决方法就是在执行 mysql_connect 之后执行以下语句

mysql_query("SET NAMES utf8");

使用phpMyAdmin-2.8.0.2完整的升级方法如下:

  1. 从原有的数据库中导出表结构和数据。
  2. 在mysql-5.0中创建数据库,设置字符校对为 utf8_general_ci。
  3. 向数据库中导入数据,导入时设置数据编码为utf8。
  4. 修改 wp-includes/wp-db.php,在wpdb类的wpdb函数中(57行前后)添加以下内容。

     function wpdb($dbuser, $dbpassword, $dbname, $dbhost) {
         $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword);
         ......
         $this->query("SET NAMES utf8");          // 添加这一行
         $this->select($dbname);
     }
    

mysql-5-update.png

(Read More)

Apache2+mod_perl环境下的HTTP处理模型

本文参考了 mod_perl 的官方文档之一, 但并不是原文档的翻译。

(Read More)

用 Synergy 控制多台电脑

Synergy的确是一个不可思议的软件, 在此先谢谢 smalldust 的推荐。

Synergy可以算作一款远程控制软件。一般的远程控制软件都是将服务器的画面提供给客户端使用, 而Synergy的创意很独特,它将客户端的键盘和鼠标提供给服务器使用。 这样如果你有多台电脑并且每台电脑都有自己的显示器,你可以通过 Synergy 用一组键盘和鼠标控制所有电脑, 而且每台电脑的屏幕可以连接起来,就像在同一台电脑上使用多个显示器一样。 下面介绍一下使用方法,所用版本为 1.3.1。

(Read More)

为WordPress添加标签输入框

用过 del.icio.us 的人一定知道,该网站的标题栏后面有一个标签输入框, 在输入框中输入标签名即可直接跳转到想要看的标签,而不必从纷繁芜杂的标签云中去寻找。 如果你在 WordPress 中添加了标签云, 一定也想在标题栏后添加一个类似于 del.icio.us 那样的输入框吧。

这里是仿照 del.icio.us 制作的标签输入框代码。crumb.zip 使用方法如下。

  1. 首先按照这个方法打开永久链接。
  2. 下载 prototype,然后将 prototype 和本文附带的 crumb.js 放到你的主题目录下的 js/ 目录下,然后在主题的 header.php 的 <head> 标记内加入以下代码。

     <script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/js/prototype.js"></script>
     <script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/js/crumb.js"></script>
    
  3. 在你想加入标签输入框的地方加入以下代码(通常是在blog的标题后)。

    <h1 id="pagetitle">
      <a id="top"></a><a href="<?php echo get_settings('home'); ?>/"><?php bloginfo('name'); ?></a>
      <!-- 上面是blog标题,下面是标签输入框的代码 -->
      / <span id="crumb"><?php echo single_cat_title(); ?></span>
      <script>
        if(Crumb) 
          Crumb.go('crumb', '<?php echo get_settings('home').get_settings('category_base').'/'; ?>');
      </script>
      <!-- 标签输入框代码结束 -->
    </h1>
    
  4. 最后在主题的 style.css 中增加以下代码,以定义标签输入框的样式。

    span#crumb input {
      font-size: 0.7em;
      font-family:verdana,sans-serif;
      background-color: #FFFFFF;
      border: solid 1px #DDDDDD;
      color: #808080;
    }
    span#crumb input.crumb-focus {
      border: solid 1px #000000;
      color: #000000;
    }
    

(Read More)

如何创建守护进程

如何在Linux下创建这样一个程序,执行之后返回shell,但程序本身驻留在内存之中继续执行?其实很简单,创建一个子进程,然后父进程结束即可。例如下面的Perl程序:

#!/usr/bin/perl
exit if fork();       # 创建子进程,然后父进程退出
while (1) { sleep 1; }       # 测试用死循环

不过需要考虑到一点,守护进程通常在系统启动时以root身份启动,但是由于安全问题,通常并不以root身份运行。这一点使用perl如何实现呢?可以使用下面的 sudo 函数。

sub sudo {
    my ($user, $group) = @_;
    my $uid = (getpwnam($user))[2];
    my $gid = (getgrnam($group))[2];
    ($(, $)) = ($gid, "$gid $gid");
    ($<, $>) = ($uid, $uid);
}

所以,一个基本的守护程序应当这样写:(sudo函数代码省略)

#!/usr/bin/perl
&sudo("myuser", "mygroup");     # myuser、mygroup为启动守护进程的用户和组
exit if fork();
while (1) { sleep 1; }

(Read More)

Linux下的常用信号

信号 动作 解释
SIGHUP 1 终端线路挂断
SIGINT 2 Term 键盘输入的中断命令,从终端输入 Ctrl-C 时发生
SIGQUIT 3 Core 键盘输入的退出命令
SIGILL 4 Core 错误指令
SIGABRT 6 Core abort(3)发出的中止信号
SIGFPE 8 Core 浮点数异常
SIGKILL 9 Term KILL信号
SIGSEGV 11 Core 非法内存访问
SIGPIPE 13 Term 管道断开
SIGALRM 14 Term alarm(2)发出的中止信号
SIGTERM 15 Term 强制中止信号
SIGUSR1 30,10,16 Term 用户自定义信号1
SIGUSR2 31,12,17 Term 用户自定义信号2
SIGCHLD 20,17,18 Ign 子进程中止信号
SIGCONT 19,18,25 Cont 继续执行一个停止的进程
SIGSTOP 17,19,23 Stop 非终端来的停止信号
SIGTSTP 18,20,24 Stop 终端来的停止信号
SIGTTIN 21,21,26 Stop 后台进程读终端
SIGTTOU 22,22,27 Stop 后台进程写终端

常用的包括 SIGHUP(服务进程重起)、SIGKILL(进程结束)等。

(Read More)

显示TagCloud: 插件Weighted Categories修改版

WordPress有个很好用的插件:Weighted Categories, 它能够将分类名显示成tag cloud,即文章数多的分类使用大号字体,文章数少的分类使用小号字体。 但是这个插件有两个问题,一是最后一个分类的链接不正确,这一点官方主页上也有人提出过; 二是各个级别的分类的样式是通过计算得出的,无法自定义样式。

针对以上两个问题,我修改了这个插件,并将其汉化。新的插件可以在这里下载。weighted-categories.zip

使用时将 weighted-categories.php 放到 wp-content/plugins 下,然后在管理面板中激活该插件。 然后在模板中加入以下的代码以显示tagcloud。

<div id="tagcloud">
<?php weighted_categories(1, 10, ""); ?>
</div>

然后需要在模板的 style.css 中加入你自己的分类级别样式定义(必须,否则各个级别显示出来都一个样)。 附带的 style-sample.css 为示例。

修改后的 weighted_categories 定义如下:

function weighted_categories($minlevel=1, $maxlevel=10, $exclude_categories)
  - $minlevel: 最小级别的编号
  - $maxlevel: 最大级别的编号
  - $exclude_categories: 不想显示的分类id,使用逗号分割,例如 "1,25"表示不显示 id 为 1 或 25 的分类

当然,为了让这些标签看起来更像真正的标签,我们需要在WordPress的选项中打开永久链接, 并在选项->永久链接分类基础选项中填入“/tag”,这样分类的链接就会显示为 /tag/分类名。

(Read More)

Ubuntu下apache+mysql+php安装memo

下载并安装 httpd 2.2。

$ tar xjvf httpd-2.2.3.tar.bz2
$ cd httpd-2.2.3/
$ ./configure --enable-rewrite --enable-so
$ make
$ sudo make install

下载并安装 mysql-3.23

$ sudo tar xzvf mysql-3.23.58-pc-linux-i686.tar.gz -C /usr/local/mysql
$ sudo groupadd mysql
$ sudo useradd -d /usr/sbin -s /bin/false -g mysql mysql
$ sudo chown -R mysql.mysql /usr/local/mysql
$ cd  /usr/local/mysql
$ sudo ./scripts/mysql_install_db
$ sudo cp support-files/mysql.server /etc/init.d/mysql
$ /etc/init.d/mysqld start

下载并安装 php 5.1.6。

$ sudo apt-get install flex bison libxml2-dev
$ tar xjvf php-5.1.6.tar.bz2
$ cd php-5.1.6/
$ ./configure --with-apxs2=/usr/local/apache2/bin/apxs --with-gd
                  --with-gettext --with-mysql --with-zlib-dir=/usr/lib 
                  --with-mysql=/usr/local/mysql

(Read More)