Blog

pg_ctl

Content #

There are two ways to make pg_ctl aware of where the PGDATA is:

  1. Setting an environment variable named PGDATA, containing the path of the data directory
  2. Using the –D command-line flag to specify the path to the data directory

There are three ways of stopping a cluster:

  1. The smart mode means that the PostgreSQL cluster will gently wait for all the connected clients to disconnect and only then will it shut the cluster down.
  2. The fast mode will immediately disconnect every client and will shut down the server without having to wait.Getting to Know Your Cluster
  3. The immediate mode will abort every PostgreSQL process, including client connections, and shut down the cluster in a dirty way, meaning that the server will need some specific activity on the restart to clean up such dirty data (more on this in the next chapters).

From #

将程序常驻内存

将程序常驻内存 #

  1. 安装DBMS_SHARED_POOL软件包:
@?/rdbms/admin/dbmspool.sql;
  1. 查看HR用户的存储过程
select object_name,object_type from dba_objects where object_type='PROCEDURE' and owner='HR';
  1. 查看SECURE_DML存储过程的内容
select line,text from dba_source where name='SECURE_DML';
  1. 将SECURE_DML常驻内存
execute dbms_shared_pool.keep('HR.SECURE_DML');
  1. 确认该存储过程是否在共享池中
select name,namespace,sharable_mem,executions,kept from v$db_object_cache where owner='HR';
  1. 将该存储过程清除出内存
execute dbms_shared_pool.unkeep('HR.SECURE_DML');

执行过上面操作后,该过程仍有可能在内存中,但kept属性为NO。

From #

将数据常驻内存

将数据常驻内存 #

Database Buffer Cache有三个池:默认池(default pool),保持池(keep pool),回收池(recycle pool)。对于用户频繁访问的表或索引,可以放置在这keep pool中,放在default pool中的数据块也可频繁访问,但这些数据会老化而退出default pool。

  1. 查看keep pool大小
show parameter db_keep_cache_size
  1. 查看当前数据库缓冲区
select id,name,block_size,buffers from v$buffer_pool;
  1. 收集需要保存到keep pool中的对象的最新统计信息
analyze index scott.SCOTT_EMP_INCOME_IDX compute statistics;
analyze table scott.salgrade compute statistics;
  1. 从dba_segments中查询出需要保存到keep spool中的对象所用的块的数量
select segment_name,segment_type,blocks from dba_segments where owner='SCOTT' and segment_name in ('XXX','XXXX');
  1. 计算出所需容量并设置大小
alter system set db_keep_cache_size=10M;
  1. 用第2步相同的操作确认keep pool的创建
  2. 将对象设置为常驻内存
alter table salgrade storage(buffer_pool keep);
alter index scott_emp_idx storage(buffer_pool keep);
  1. 将对象恢复为默认缓冲池
alter table salgrade storage(buffer_pool default);
  1. 确认对象所在缓冲池
select table_name,tablespace_name,buffer_pool from user_tables where table_name='SALGRADE';
select index_name,table_name,buffer_pool from user_indexes where index_name='XXX_IDX';

From #

自动PGA管理(Automatic PGA Memory Management)

自动PGA管理(Automatic PGA Memory Management) #

如果启用“自动PGA管理”,则*_AREA_SIZE参数的值都将被忽略。 PGA_AGGREGATE_TARGET为非0时,即启用“自动PGA管理”,通常 PGA_AGGREGATE_TARGET的值为SGA的20%。PGA_AGGREGATE_TARGET的值会根据系统的需求动态改变,但可以通过ALTER SYSTEM来改变初始值。

ALTER SYSTEM SET WORKAREA_SIZE_POLICY=AUTO;

From #

配置SGA静态参数

配置SGA静态参数 #

  1. LOCK_SGA

LOCK_SGA的作用是将SGA锁定在物理内存内,这样就不会出现SGA使用虚拟内存的情况,显然这样可以提高数据的读取速度。可用下面的命令修改:

alter system set lock_sga=true scope=spfile;

该参数为静态参数,需要重启数据库才会生效。该参数与SGA_TARGET不能同时设置,否则会提示如下错误:

ORA-00847: MEMORY_TARGET/MEMORY_MAX_TARGET and LOCK_SGA cannot be set together

从MEMORY_TARGET改用LOCK_SGA会有很多问题,一般需要先将MEMORY_TARGET、 SGA_TARGET设置为0,重启,再设置DB_CACHE_SIZE、SHARED_POOL_SIZE等参数,再重启。如果发现MEMORY_MAX_TARGET没有被改变,那么可能需要运行下面的语句:

ALTER SYSTEM RESET MEMOYR_MAX_TARGET

改这个参数之前要反复检查环境是否满足条件,并且一定要做好spfile的备份,一般是创建pfile备份,以防万一重启失败时能够恢复spfile。

设置该参数还需要特别注意修改系统默认资源限制,默认情况下Linux系统的用户只能锁定64K内存,此时使用LOCK_SGA会导致ORA-27102: out of memory。需要在系统limits.conf文件中添加如下配置:

oracle		    -	    memlock 3072000
  1. PRE_PAGE_SGA

该参数的作用是启动数据库实例时,将整个SGA读入物理内存,对于内存充足的系统而言,这样显然可以提高系统运行效率。

From #

自动SGA管理(Automatic Shared Memory Management)

自动SGA管理(Automatic Shared Memory Management) #

  1. 把数据库的统计级别设置成TYPICAL或ALL
ALTER SYSTEM SET STATISTICS_LEVEL=TYPICAL;
  1. 计算SGA的目标值(SGA_TARGET)
(SELECT SUM(value) FROM V$SGA) - (SELECT CURRENT_SIZE FROM V$SGA_DYNAMIC_FREE_MEMORY)
  1. 设置SGA目标值
ALTER SYSTEM SET SGA_TARGET = 1000M SCOPE=BOTH;
  1. 把SGA相关内存组件的大小设置为0

SHARED_POOL_SIZE, LARGE_POOL_SIZE, JAVA_POOL_SIZE, DB_CACHE_SIZE, STREAMS_POOL_SIZE

From #

PGA(Program Global Area)

PGA(Program Global Area) pga #

  1. 会话内存区(Session Memory)
  2. 私有SQL区存放绑定变量的值、查询执行的状态信息、查询执行工作区、游标。 Dedicated Server Mode,私有SQL区位于PGA中。Shared Server Mode,私有SQL区一部分位于SGA,一部分位于PGA。下面的操作会用到查询执行工作区(Query Execution Work Areas):
    • 涉及排序的操作(order by, group by, roolup, window function)
    • 哈希连接(Hash-Join)
    • 位图合并(Bitmap Merge)
    • 位图创建(Bitmap Create)

From #

SGA(System Global Area)

SGA(System Global Area) sga #

数据库高速缓冲区(Database Buffer Cache) #

该区域存放用户从数据库读取的数据,在用户查找数据库时会首先在数据库缓冲区中搜索,如果没有才会读取数据库文件,所以该区域不能设置过小。

重做日志缓冲区(Redo Log Buffer) #

该缓冲区放置用户改变的数据,所有变化了的数据和回滚需要的数据都暂时保存在重做日志缓冲区中,涉及的参数为log_buffer,可通过下面的命令查看:

show parameter log_buffer

共享池(Shared Pool) #

库缓冲区(Library Cache) #

  1. 共享SQL区(Shared SQL Area) SQL语句的解析树的执行计划
  2. 私有SQL区(Private SQL Area) SQL语句的绑定变量、环境、会话参数,以及PL/SQL程序的局部变量、全局变量、包变量
  3. PL/SQL过程和包
  4. 控制结构(Control Structure)

字典缓冲区(Dictionary Cache) #

结果缓冲区(Result Cache) #

大池(Large Pool) #

Java池(Java Pool) #

流池(Streams Pool) #

常用视图和操作 #

show sga
v$sga, v$sgainfo, v$sgastat, v$memory_dynamic_components
v$memory_target_advice 提供了调校自动内存管理的建议
ALTER SYSTEM FLUSH SHARED_POOL 清空共享池

Question Engine(Moodle)

Question Engine #

一次Quiz Attempt可以拆分成若干次Question Attempt。学生参加一次Quiz Attempt,就好像参加多次独立的Question Attempt,然后把多个Question Attempt的结果综合在一起。

数据库表的含义 #

根据测验的cmid可从m_context中查出该模块的contextid,再根据该contextid可查出所有m_question_usages的id,每个m_question_usages的id对应多条m_question_attempts记录(如果该测验有6题,则每个question_usage会对应6个question_attempt)。 quiz_attempts表的uniqueid为question_usages的id。先查出Quiz的id,再到quiz_attempts中查uniqueid,就能得到本次测验的所有question_usages的id,然后再查出question_attempts的所有id。课程页面URL中显示的id均为m_course_modules表的id。如果要查quiz在m_quiz中的id,需要m_course_modules和m_modules结合起来查。

假定某测验共有10题,某学生参加一次测验,就会是一次question_usage,会有独立的question_usage_id,该question_usage会包含10条question_attempt记录,每条question_attempt对应一道题目。为什么userid出现在question_attempt_steps表中,而不是出现在question_usages表中,或question_attempts表?有没有可能出现同一个question_attempt,却由不同的用户来完成?根据对某次测验数据表的数据分析,每次question_usage只会有一个用户ID,没有出现同一次question_usage中有两个不同用户的情形。是设计者没有想到吗?

question_usages记录题库(Question Bank)的使用,Moodle2.7的数据显示,目前使用Question Bank的component只有mod_quiz和core_question_preview,以后可能会有其它插件来使用Question Bank。如果不考虑到可能有其它插件使用Question Bank的话,那么可以不用question_usages,只要有quiz_attempts表就可以了。学生参加一次测验,就会生成一条quiz_attempt记录,quiz_attempt记录又会包含多条question_attempt记录。有了question_usages,那就变成了,一次测验会生成quiz_attempt记录,还会生成一条question_usages记录,再由question_usages记录对应多条question_attempt记录。quiz_attempts与question_usages应该是一对一关联,但question_usages包含有与quiz_attempts表对应记录之外的记录。

这样看起来,question_attempt_steps表中的userid是冗余的数据,或许只是考虑到性能问题,避免一次连接过多的表,才加入的userid字段。quiz_attempts表有userid,由此就可以查出该用户在该quiz中的所有记录,只不过涉及的表很多: quiz_attempts -> question_usages -> question_attempts -> question_attempt_steps -> question_attempt_step_data

查询 #

  1. 连接M_USER,M_QUESTION_ATTEMPT_STEPS,M_QUESTION_ATTEMPTS,M_QUESTION可查出用户在某题目上的所有的尝试。

题型 #

完型填空 #

完形填空题会被拆成多个填空题,原来题干中需要填空的地方(如{SAC:final})会被替换成{#1},{#2}这样的符号,保存到question表中。接下来分析每个填空位置的符号,每个填空位置会被拆分成一个填空题,题目和答案分别写入question表和question_answers表。最后需要在question_multianswer表中记下相应位置对应题目题的id及顺序。比如:

mysql> select * from mdl_question_multianswer;

 id   question   sequence 
  1          2   3,4      

上表说明,id为2的cloze题目中,其填空位置分别由id为3,4的填空题组成。

多选题 #

题干保存在question表中,每个选项保存在question_answers表中,每个选项会设置比例分值(fraction),选项答案正确与否,完全取决于fraction的值。因此选项的数量可以任意,正确答案的数量由应用程序计算得出,如果需要选中三个才算完成的话,每个正确选项的分值就是33.3333%了。 qtype_multichoice_options表中记录了该多选题的一些参数,如:是否更换选项次序,是否单选,选项编号的格式等等。

...