Oracle 启动流程详解:NOMOUNT / MOUNT / OPEN
Oracle 启动流程详解:NOMOUNT / MOUNT / OPEN
适用版本:Oracle Database 11g / 12c / 19c / 23ai 阅读基础:了解 Oracle 实例与数据库的概念、参数文件 PFILE/SPFILE 文档版本:v1.0 / 2026-07
目录
- 1. 概述:启动流程的三阶段模型
- 2. NOMOUNT 阶段(实例启动)
- 3. MOUNT 阶段(数据库装载)
- 4. OPEN 阶段(数据库打开)
- 5. 启动命令的完整语法
- 6. 数据库关闭流程
- 7. 启动限制模式
- 8. 静默模式与挂起模式
- 9. 启动相关视图
- 10. 常见坑与排错
- 11. 最佳实践
- 12. 参考资料
1. 概述:启动流程的三阶段模型
Oracle 数据库的启动过程是一个严格分阶段的过程,每阶段完成特定任务并产出特定状态[1]。理解三阶段模型是 DBA 的基本功,也是排错的核心知识。
+----------------+ +----------------+ +----------------+
| NOMOUNT | -> | MOUNT | -> | OPEN |
| (实例启动) | | (数据库装载) | | (数据库打开) |
+----------------+ +----------------+ +----------------+
读取参数文件 读取控制文件 打开数据文件/Redo
分配 SGA 定位数据文件 验证一致性
启动后台进程 锁定控制文件 实例恢复
三阶段对照表:
| 阶段 | 状态 | 读取的文件 | 可执行操作 |
|---|---|---|---|
| NOMOUNT | 实例已启动 | 参数文件(PFILE/SPFILE) | CREATE DATABASE、CREATE CONTROLFILE |
| MOUNT | 数据库已装载 | 参数文件 + 控制文件 | DB 维护操作(重命名文件、归档模式切换) |
| OPEN | 数据库已打开 | 参数文件 + 控制文件 + 数据文件 + Redo Log | 全部正常 DML/DDL/查询 |
直接打开命令:
STARTUP;
-- 等价于
STARTUP OPEN;
-- 等价于:NOMOUNT -> ALTER DATABASE MOUNT -> ALTER DATABASE OPEN
分阶段启动命令:
-- 1. 只启动实例
STARTUP NOMOUNT;
-- 2. 装载数据库
ALTER DATABASE MOUNT;
-- 3. 打开数据库
ALTER DATABASE OPEN;
2. NOMOUNT 阶段(实例启动)
2.1 NOMOUNT 做了什么
NOMOUNT 阶段只启动实例(Instance),不涉及数据库文件[1][2]:
- 读取参数文件:按
spfile<SID>.ora→spfile.ora→init<SID>.ora顺序查找 - 解析参数:获取
sga_target、processes、db_name等配置 - 分配 SGA:根据参数在内存中分配 System Global Area
- 启动后台进程:PMON、SMON、DBWn、LGWR、CKPT、ARCn、MMON、RECO 等
- 打开警报日志:在
diagnostic_dest下创建/打开 alert log - 校验参数合法性:如
db_block_size必须是 2K/4K/8K/16K/32K 之一
命令:
STARTUP NOMOUNT;
警报日志中的输出示例:
Sun Jul 21 10:23:15 2026
Starting ORACLE instance (normal)
LICENSE_MAX_SESSION = 0
LICENSE_SESSIONS_WARNING = 0
Initial number of CPU is 8
CELL communication is configured to use 0 TCP/IP sockets
...
System parameters with non-default values:
processes = 300
sga_target = 4G
control_files = "/u01/oradata/orcl/control01.ctl"
control_files = "/u02/oradata/orcl/control02.ctl"
db_block_size = 8192
compatible = "19.0.0"
undo_tablespace = "UNDOTBS1"
...
PMON started with pid=2, OS id=1234
SMON started with pid=3, OS id=1235
DBW0 started with pid=4, OS id=1236
LGWR started with pid=5, OS id=1237
CKPT started with pid=6, OS id=1238
...
2.2 NOMOUNT 后的内存与进程
NOMOUNT 完成后,可以从 OS 视角看到:
# 查看 Oracle 后台进程
ps -ef | grep ora_ | grep orcl
# 输出
oracle 1234 1 0 10:23 ? 00:00:00 ora_pmon_orcl
oracle 1235 1 0 10:23 ? 00:00:00 ora_smon_orcl
oracle 1236 1 0 10:23 ? 00:00:00 ora_dbw0_orcl
oracle 1237 1 0 10:23 ? 00:00:00 ora_lgwr_orcl
oracle 1238 1 0 10:23 ? 00:00:00 ora_ckpt_orcl
oracle 1239 1 0 10:23 ? 00:00:00 ora_arc0_orcl
oracle 1240 1 0 10:23 ? 00:00:00 ora_mmon_orcl
-- 查询实例状态
SELECT instance_name, status FROM v$instance;
-- INSTANCE_NAME STATUS
-------------------------
-- orcl STARTED
-- 查看 SGA 分配
SELECT * FROM v$sgainfo;
-- 查看后台进程
SELECT name, description, pid FROM v$bgprocess WHERE paddr <> '00';
2.3 NOMOUNT 的使用场景
NOMOUNT 状态下数据库尚未装载,但实例已经活,主要用于:
- 创建数据库(CREATE DATABASE)
- 重建控制文件(CREATE CONTROLFILE)
- 恢复控制文件(如全部控制文件丢失,需先到 NOMOUNT 再 restore)
- 查看 SGA/PGA 配置
- RMAN 恢复时:
RESTORE CONTROLFILE FROM AUTOBACKUP;
-- 创建新数据库示例
STARTUP NOMOUNT PFILE='/u01/init_newdb.ora';
CREATE DATABASE newdb
USER SYS IDENTIFIED BY ******
USER SYSTEM IDENTIFIED BY ******
LOGFILE GROUP 1 ('/u01/oradata/newdb/redo01.log') SIZE 100M,
GROUP 2 ('/u01/oradata/newdb/redo02.log') SIZE 100M,
GROUP 3 ('/u01/oradata/newdb/redo03.log') SIZE 100M
MAXLOGFILES 5
MAXLOGMEMBERS 5
MAXLOGHISTORY 1
MAXDATAFILES 100
CHARACTER SET AL32UTF8
NATIONAL CHARACTER SET AL16UTF16
EXTENT MANAGEMENT LOCAL
DATAFILE '/u01/oradata/newdb/system01.dbf' SIZE 500M REUSE
SYSAUX DATAFILE '/u01/oradata/newdb/sysaux01.dbf' SIZE 500M REUSE
DEFAULT TABLESPACE users
DATAFILE '/u01/oradata/newdb/users01.dbf' SIZE 500M REUSE
DEFAULT TEMPORARY TABLESPACE tempts1
TEMPFILE '/u01/oradata/newdb/temp01.dbf' SIZE 200M REUSE
UNDO TABLESPACE undotbs1
DATAFILE '/u01/oradata/newdb/undotbs01.dbf' SIZE 200M REUSE;
3. MOUNT 阶段(数据库装载)
3.1 MOUNT 做了什么
MOUNT 阶段在 NOMOUNT 基础上完成[1][3]:
- 读取控制文件:根据参数文件中
control_files参数定位控制文件 - 校验控制文件一致性:所有多路复用的控制文件必须一致
- 锁定控制文件:实例获得对控制文件的独占访问(RAC 除外)
- 读取数据库元数据:从控制文件中读取数据文件、Redo Log 文件的位置信息
- 不打开数据文件:数据文件此时还未打开
命令:
-- 从 NOMOUNT 进入 MOUNT
ALTER DATABASE MOUNT;
-- 或直接启动到 MOUNT
STARTUP MOUNT;
警报日志输出:
Sun Jul 21 10:25:42 2026
ALTER DATABASE MOUNT
Successful mount of redo thread 1, with mount id 4157832108
Database mounted in Exclusive Mode
Lost write protection disabled
Completed: ALTER DATABASE MOUNT
状态查询:
SELECT instance_name, status FROM v$instance;
-- INSTANCE_NAME STATUS
-------------------------
-- orcl MOUNTED
-- 查看控制文件
SELECT name, status FROM v$controlfile;
-- 查看数据文件(MOUNT 状态下可见但未打开)
SELECT name, status, checkpoint_change# FROM v$datafile;
3.2 MOUNT 阶段可执行的操作
MOUNT 状态下可以执行DB 维护类操作,但不能执行 DML/DDL:
-- 切换归档模式(必须在 MOUNT 状态)
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE NOARCHIVELOG;
-- 重命名数据文件(需 OFFLINE 数据文件)
ALTER DATABASE RENAME FILE '/u01/old.dbf' TO '/u02/new.dbf';
-- 启用闪回数据库
ALTER DATABASE FLASHBACK ON;
-- 改变数据库字符集(部分场景)
ALTER DATABASE CHARACTER SET AL32UTF8;
-- RMAN 备份/恢复(部分操作)
-- RESTORE DATABASE / RECOVER DATABASE
-- 启用/禁用补充日志
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
-- 修改数据文件状态
ALTER DATABASE DATAFILE '/u01/users.dbf' OFFLINE;
3.3 MOUNT 的使用场景
- 切换归档模式:
ALTER DATABASE ARCHIVELOG必须在 MOUNT 状态执行 - 数据库完全恢复:系统表空间数据文件损坏时,需在 MOUNT 状态恢复
- RMAN 备份/恢复:很多 RMAN 操作在 MOUNT 状态下进行
- 更改数据库闪回状态
- 数据文件迁移:重命名数据文件路径
- 更改字符集
4. OPEN 阶段(数据库打开)
4.1 OPEN 做了什么
OPEN 阶段是最后一个阶段,完成数据库正常可用的全部准备[1]:
- 打开数据文件:根据控制文件中记录的位置,打开所有 ONLINE 数据文件
- 打开 Redo Log 文件:打开在线 Redo Log 文件
- 验证一致性:
- 检查数据文件头的 SCN 与控制文件中记录的 SCN 是否一致
- 检查 Redo Log 的 Sequence 是否正确
- 实例恢复(如需要):如果上次关闭非正常,自动执行实例恢复
- 撤销未提交事务:使用 Undo 数据回滚未提交事务
- 生成新的 Redo 记录:开始接受 DML 操作
命令:
-- 从 MOUNT 进入 OPEN
ALTER DATABASE OPEN;
-- 或直接启动到 OPEN
STARTUP;
STARTUP OPEN;
警报日志输出:
Sun Jul 21 10:28:11 2026
ALTER DATABASE OPEN
Beginning opening data files
Online datafile 1
Online datafile 2
...
Online datafile 7
Opening online redo log 1
Opening online redo log 2
Opening online redo log 3
Database opened.
Completed: ALTER DATABASE OPEN
状态查询:
SELECT instance_name, status FROM v$instance;
-- INSTANCE_NAME STATUS
-------------------------
-- orcl OPEN
-- 查看数据文件状态
SELECT name, status, checkpoint_change# FROM v$datafile;
-- 查看数据库打开模式
SELECT name, open_mode, log_mode FROM v$database;
-- NAME OPEN_MODE LOG_MODE
---------------------------------------
-- orcl READ WRITE ARCHIVELOG
4.2 OPEN 阶段的实例恢复
如果上次数据库非正常关闭(如实例崩溃、SHUTDOWN ABORT、断电),OPEN 阶段会自动执行实例恢复[3]:
- 前滚(Roll Forward):从 Redo Log 中重做未写入数据文件的已提交事务
- 打开数据库:数据文件达到一致状态后打开数据库
- 回滚(Roll Back):使用 Undo 数据回滚未提交事务(在后台异步执行)
警报日志示例:
Sun Jul 21 10:30:15 2026
ALTER DATABASE OPEN
Beginning crash recovery of 1 threads
parallel recovery started with 4 processes
Started redo scan
Completed redo scan
read 512 KB redo, 152 data blocks need recovery
Started redo application at
Thread 1: logseq 245, block 1024
Recovery of Online Redo Log: Thread 1 Group 2 Seq 245 Reading mem 0
Completed redo application of 0.05MB
Crash recovery applied 152 redo records and 152 data blocks
Completed crash recovery at
Thread 1: logseq 245, block 1320, scn 1234567890
48 data blocks read, 48 data blocks written, 152 redo records read
Database opened.
OPEN 模式选项:
-- 只读模式打开
ALTER DATABASE OPEN READ ONLY;
-- 限制模式打开(仅 DBA 可登录)
ALTER DATABASE OPEN RESTRICT;
5. 启动命令的完整语法
STARTUP 命令完整语法[1]:
STARTUP [FORCE] [RESTRICT] [PFILE=filename]
[MOUNT | OPEN [OPEN clauses] | NOMOUNT];
| 选项 | 说明 |
|---|---|
FORCE | 先 ABORT 再 STARTUP(强制重启,慎用) |
RESTRICT | 以限制模式启动,仅允许 RESTRICTED SESSION 权限用户登录 |
PFILE=filename | 显式指定 PFILE 文件路径 |
MOUNT | 启动到 MOUNT 状态 |
OPEN | 启动到 OPEN 状态(默认) |
NOMOUNT | 启动到 NOMOUNT 状态 |
常见组合:
-- 强制重启(生产慎用)
STARTUP FORCE;
-- 限制模式启动(用于维护)
STARTUP RESTRICT;
-- 指定 PFILE 启动
STARTUP PFILE='/u01/backup/initorcl.ora' NOMOUNT;
-- 只读模式
STARTUP MOUNT;
ALTER DATABASE OPEN READ ONLY;
-- 升级模式(数据库升级时使用)
STARTUP UPGRADE;
6. 数据库关闭流程
数据库关闭与启动相反,分四步[1]:
1. CLOSE:关闭数据文件和 Redo Log
2. DISMOUNT:关闭控制文件
3. 关闭实例:释放 SGA、停止后台进程
6.1 SHUTDOWN NORMAL
- 行为:等待所有用户主动断开
- 特点:
- 不允许新连接
- 等待当前所有会话断开
- 关闭前执行 checkpoint
- 启动时不需要实例恢复
- 适用场景:维护窗口宽裕、需等待用户主动退出
SHUTDOWN;
-- 等价于
SHUTDOWN NORMAL;
6.2 SHUTDOWN TRANSACTIONAL
- 行为:等待所有活动事务完成
- 特点:
- 不允许新连接
- 不允许新事务(已连接客户端启动新事务会报错)
- 等待当前事务提交或回滚
- 关闭前执行 checkpoint
- 启动时不需要实例恢复
- 适用场景:希望最小化干预的关闭
SHUTDOWN TRANSACTIONAL;
6.3 SHUTDOWN IMMEDIATE
- 行为:立即回滚所有未提交事务并关闭
- 特点:
- 不允许新连接
- 立即回滚未提交事务(可能耗时)
- 关闭前执行 checkpoint
- 启动时不需要实例恢复
- 适用场景:日常维护、紧急关闭但保证数据一致
SHUTDOWN IMMEDIATE;
6.4 SHUTDOWN ABORT
- 行为:直接终止实例,不回滚、不 checkpoint
- 特点:
- 不允许新连接,立即断开所有会话
- 不执行 checkpoint
- 不回滚未提交事务
- 启动时必须执行实例恢复
- 适用场景:
- 实例已挂死,其他 SHUTDOWN 方式失效
- 数据库即将断电前的紧急操作
- 启动后立即备份的场景
SHUTDOWN ABORT;
对比表:
| 模式 | 新连接 | 当前事务 | Checkpoint | 实例恢复 |
|---|---|---|---|---|
| NORMAL | 拒绝 | 等待完成 | 是 | 否 |
| TRANSACTIONAL | 拒绝 | 等待完成 | 是 | 否 |
| IMMEDIATE | 拒绝 | 回滚 | 是 | 否 |
| ABORT | 拒绝 | 不处理 | 否 | 是 |
7. 启动限制模式
限制模式(RESTRICTED SESSION)下,只有拥有 RESTRICTED SESSION 系统权限的用户才能连接:
-- 启动到限制模式
STARTUP RESTRICT;
-- 已启动后切换为限制模式
ALTER SYSTEM ENABLE RESTRICTED SESSION;
-- 退出限制模式
ALTER SYSTEM DISABLE RESTRICTED SESSION;
-- 授予限制模式权限
GRANT RESTRICTED SESSION TO dba_user;
适用场景:
- 数据结构维护
- 数据导出/导入
- 性能测试
- 修复对象失效
8. 静默模式与挂起模式
8.1 静默模式(Quiesce)
让数据库进入”静止”状态,所有非 DBA 会话的活动暂停:
-- 进入静默
ALTER SYSTEM QUIESCE RESTRICTED;
-- 退出静默
ALTER SYSTEM UNQUIESCE;
与 RESTRICT 区别:
| 特性 | RESTRICT | QUIESCE |
|---|---|---|
| 现有会话 | 立即断开 | 挂起,不执行任何操作 |
| 新会话 | 仅 DBA 可连接 | 仅 DBA 可连接 |
| 适用场景 | 维护操作 | 在线操作期间需要”快照” |
8.2 挂起模式(SUSPEND)
暂停所有 I/O 操作,用于存储级快照:
ALTER SYSTEM SUSPEND;
-- 此时所有 I/O 暂停
-- 存储层做快照
ALTER SYSTEM RESUME;
适用场景:存储快照备份、Split-mirror 备份方案
9. 启动相关视图
9.1 V$INSTANCE
SELECT instance_name, status, database_status,
startup_time, version
FROM v$instance;
| 列 | 含义 |
|---|---|
status | STARTED(NOMOUNT)/ MOUNTED / OPEN |
database_status | ACTIVE / SUSPENDED |
startup_time | 实例启动时间 |
9.2 V$DATABASE
SELECT name, open_mode, log_mode, flashback_on,
checkpoint_change#, current_scn
FROM v$database;
| 列 | 含义 |
|---|---|
open_mode | READ WRITE / READ ONLY / MOUNTED |
log_mode | ARCHIVELOG / NOARCHIVELOG |
flashback_on | YES / NO |
9.3 V$THREAD
SELECT thread#, status, instance,
sequence#, checkpoint_change#
FROM v$thread;
9.4 查看启动日志
# 警报日志路径
$ORACLE_BASE/diag/rdbms/orcl/orcl/trace/alert_orcl.log
# 实时监控启动过程
tail -f $ORACLE_BASE/diag/rdbms/orcl/orcl/trace/alert_orcl.log
10. 常见坑与排错
10.1 ORA-01078:参数文件问题
现象:
ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file '/u01/app/oracle/product/19.3.0/dbhome_1/dbs/initorcl.ora'
排查:
# 1. 确认 ORACLE_SID
echo $ORACLE_SID
# 2. 确认 ORACLE_HOME
echo $ORACLE_HOME
# 3. 查找参数文件
ls -l $ORACLE_HOME/dbs/
# 4. 如果只有 SPFILE,无 PFILE,可能是 SID 配置错误
# 检查 /etc/oratab
cat /etc/oratab
10.2 ORA-00205:控制文件问题
现象:
ORA-00205: control file open error, check alert log for more info
原因:
- 控制文件不存在或路径错误
- 控制文件损坏
- 权限不足
排查:
-- 启动到 NOMOUNT(不需控制文件)
STARTUP NOMOUNT;
-- 查看参数文件中控制文件配置
SHOW PARAMETER control_files;
-- 检查文件是否存在
! ls -l /u01/oradata/orcl/control*.ctl
10.3 ORA-01102:数据库已被挂载
现象:
ORA-01102: cannot mount database in EXCLUSIVE mode
原因:
- 另一个实例已经 MOUNT 了数据库
- 之前的实例未正确关闭,残留共享内存
修复:
# 1. 检查是否有其他 Oracle 进程
ps -ef | grep ora_pmon_$ORACLE_SID
# 2. 如果有,先用该实例关闭
sqlplus / as sysdba
SQL> SHUTDOWN IMMEDIATE;
# 3. 如果进程不存在但 IPC 资源未释放
ipcs -m | grep oracle
ipcrm -m <shmid>
# 4. 重新启动
STARTUP;
10.4 ORA-01113:文件需要介质恢复
现象:
ORA-01113: file 1 needs media recovery
ORA-01110: data file 1: '/u01/oradata/orcl/system01.dbf'
原因:上次异常关闭,启动时实例恢复无法完成(如 Redo Log 丢失)。
修复:
-- 启动到 MOUNT
STARTUP MOUNT;
-- 使用 RMAN 恢复
rman target /
RMAN> RECOVER DATABASE;
-- 完成后打开
SQL> ALTER DATABASE OPEN;
10.5 ORA-01589:必须用 RESETLOGS 或 NORESETLOGS 打开
现象:
ORA-01589: must use RESETLOGS or NORESETLOGS option for database open
修复:
-- 不完全恢复后必须用 RESETLOGS
ALTER DATABASE OPEN RESETLOGS;
-- 完全恢复后用 NORESETLOGS
ALTER DATABASE OPEN NORESETLOGS;
10.6 启动后无法登录:监听未启动
现象:数据库已 OPEN,但远程客户端连接报 ORA-12541: TNS:no listener。
修复:
# 1. 启动监听
lsnrctl start
# 2. 检查监听状态
lsnrctl status
# 3. 检查 listener.ora
cat $ORACLE_HOME/network/admin/listener.ora
10.7 RAC 中只有一个节点启动
现象:RAC 环境下,一个节点启动正常,另一个节点 STARTUP 失败。
排查:
# 1. 检查集群状态
crsctl stat res -t
# 2. 检查 ASM 状态
crsctl stat res ora.asm -t
# 3. 检查 SPFILE 共享位置(应在 ASM 中)
srvctl config database -d orcl
11. 最佳实践
11.1 启动前检查清单
# 1. 检查 OS 资源
df -h /u01 /u02 # 磁盘空间
free -m # 内存
uptime # 系统负载
# 2. 检查 Oracle 进程
ps -ef | grep ora_
# 3. 检查监听器
lsnrctl status
# 4. 检查 alert log 尾部
tail -50 $ORACLE_BASE/diag/rdbms/orcl/orcl/trace/alert_orcl.log
11.2 维护操作使用合适的状态
| 操作 | 推荐状态 |
|---|---|
| 创建数据库 | NOMOUNT |
| 重建控制文件 | NOMOUNT |
| 切换归档模式 | MOUNT |
| 启用闪回 | MOUNT |
| 重命名数据文件 | MOUNT |
| 系统表空间恢复 | MOUNT |
| 用户表空间恢复 | OPEN(数据文件 OFFLINE) |
| RMAN 完全备份 | MOUNT 或 OPEN |
| 修改字符集 | MOUNT(部分情况) |
11.3 关闭数据库优先级
NORMAL > TRANSACTIONAL > IMMEDIATE > ABORT
优先用 IMMEDIATE,仅当实例无响应才用 ABORT。
11.4 ABORT 后必须做检查
如果用了 SHUTDOWN ABORT,下次启动时:
- 监控 alert log 中的实例恢复过程
- 检查是否有数据文件需要介质恢复
- 启动后立即做一次完整备份
11.5 维护窗口使用 RESTRICT 模式
-- 维护前
ALTER SYSTEM ENABLE RESTRICTED SESSION;
-- 杀掉现有非 DBA 会话
SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''' IMMEDIATE;'
FROM v$session
WHERE username IS NOT NULL
AND type <> 'BACKGROUND';
-- 执行维护操作
-- ...
-- 完成后开放
ALTER SYSTEM DISABLE RESTRICTED SESSION;
11.6 定期备份 SPFILE 和控制文件
-- 备份参数文件
CREATE PFILE='/u01/backup/pfile_$(date +%Y%m%d).ora' FROM SPFILE;
-- RMAN 自动备份控制文件和 SPFILE
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON;
12. 参考资料
[1] Oracle Database Administrator’s Guide 19c, “Starting Up and Shutting Down” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/starting-and-shutting-down-oracle-database.html
[2] Oracle Database Concepts 19c, “Database Instances” https://docs.oracle.com/en/database/oracle/oracle-database/19/cncpt/database-instances.html
[3] AskTOM, “Startup Phases Explained” https://asktom.oracle.com/pls/apex/f?p=100:1:0
[4] 墨天轮,“Oracle 数据库启动与关闭原理详解” https://www.modb.pro/db/1759656813559025664
[5] Oracle Support Note 1629101.1, “Master Note: Database Startup Phases” https://support.oracle.com/epmos/faces/DocumentDisplay?id=1629101.1
[6] Jonathan Lewis Blog, “Crash Recovery Internals” https://jonathanlewis.wordpress.com