Oracle+Python适合 Oracle DBA 使用的 Python-阿里云开发者社区

开发者社区> rudy_gao> 正文

Oracle+Python适合 Oracle DBA 使用的 Python

简介: 传统上,当需要为操作系统编写一些脚本时,人们常常会选用 Bash 或 Perl 脚本工具。
+关注继续查看

传统上,当需要为操作系统编写一些脚本时,人们常常会选用 Bash 或 Perl 脚本工具。这些工具易于使用,因而它们几乎变得无处不在,渗透到了包括 Oracle Database 在内的其他软件中,Oracle Database 在很大程度上依赖它们执行各种管理任务。

但是最近,这种趋势有所转变,转向有利于 Python 这类较新的编程工具。Python 可为我们提供直观的开发以及各种灵活的数据结构和库。所有的现代 Unix 和 Linux 系统都附带了 Python;例如,Oracle Linux 6.1 附带了 Python 2.6.6。

本教程将介绍对数据库管理员尤为有用的一些 Python 特性,无论这些管理员要实现一次性代码段还是完全可重用的程序,这些特性对他们来说都十分有用。在本部分中,我们将探究如何与操作系统和远程资源交互,然后了解各种压缩和文件系统遍历模块。

出于本教程的目的,我们将在 Oracle Linux 6.1 和 Python 2.6.6 环境中使用 Oracle Database 11g 快捷版 (XE)。


与文件系统交互

Python 用来与操作系统交互的核心库是 os 模块,您可以通过此模块处理系统进程、识别平台、处理操作系统管道以及使用环境变量 — 以 100 多个函数和变量的形式。

检测当前平台如同访问 os 模块中的预定义字符串那样容易。以下示例展示了 Oracle Linux 6.1 上的结果,并且还显示了此操作系统的默认路径分隔符。

>>> import os
>>> os.name
‘posix’
>>> os.sep
‘/’

通过 os.environ 可以访问所有 Oracle 环境变量的列表。以下示例利用一个内联生成器表达式:

>>> import os
>>> oracle_vars = dict((a,b) for a,b in os.environ.items() if a.find('ORACLE')>=0)
>>> from pprint import pprint
>>> pprint(oracle_vars)
{'ORACLE_HOME': '/u01/app/oracle/product/11.2.0/xe', 'ORACLE_SID':'XE'}

这相当于

SELECT key, value 
FROM os.environ 
WHERE key LIKE ‘%ORACLE%’ 

(若用 SQL 编写)。

当我们进一步探索时,我们开始查看文件系统并了解所处位置。下表列出了最常用的文件系统访问函数及其描述。 

函数

作用

os.getcwd()

获取操作系统中的当前工作目录

os.chdir(path)

将目录更改为给定 path

os.chroot(path)

将当前 Python 进程的根路径更改为 path

os.chown(pathuidgid)

与 chmod Linux 命令相同(uid 和 gid 是编号)

os.listdir(path)

列出给定 path 下的文件和目录

os.mkdir(pathmode)

在给定 path 下创建目录,并将八进制权限设置为 mode(默认为 0777)

os.remove(path)

删除 path 下的一个文件

os.rmdir(path)

删除 path 下的目录

os.rename(pathnewpath)

将 path 重命名为 newpath

os.stat(path)

使用 OS stat() 调用显示 path 的属性

os.walk(pathtopdown,onerrorfollowlinks)

针对 path 下的文件系统树返回生成器返回字节组(路径、目录、文件)

 

掌握了支持文件系统浏览的基本功能之后,我们来了解一下如何使用 Python 快速查看旧的跟踪文件和“未轮转”日志的列表并显示它们使用了多少空间。清单 1 中的程序需要两个参数:Oracle 日志路径(DIAGNOSTIC_DEST 指向的目录)和文件被视为过时的天数。此示例基于 os.walk


清单 1. walk.py:Oracle 诊断目录下的旧的日志和跟踪文件

import datetime
import os
import sys
import time
from pprint import pprint

def readable(size):
  si=('B','KB','MB','GB','TB', 'PB', 'EB', 'ZB', 'YB')
  div = [n for n, m in enumerate(si) if pow(1024, n+1)>size][0]
  return "%.1f%s"%(size/float(pow(1024, div)), si[div])

total = {"log":0, "trace":0}
for path, dirs, files in os.walk(sys.argv[1]):
  for f in files:
    filepath = path+os.sep+f
    if os.stat(filepath).st_mtime>time.time()-(3600*24*int(sys.argv[2])):
      size = readable(os.path.getsize(filepath))
      age = datetime.datetime.fromtimestamp(os.stat(filepath).st_mtime)
      if f in ("log.xml", "alert.log", "listener.log"):
        filetype = "log"
      elif f.endswith("trc") or f.endswith("trm"):
        filetype = "trace"
      else:
        filetype = None
      if filetype:
        total[filetype] += os.path.getsize(filepath)

for a, b in total.items():
  total[a] = readable(b)

pprint(total)

运行 walk.py 得到如下输出:

$ python walk.py /home/oracle/app 10
{'log': '132.0MB', 'trace':'0.0B'}

在 os 命名空间中,另有一个名为 os.path 的模块,用于解决路径名称操作。它包含适用于不同系统的平台敏感的实现,因此导入 os.path 将始终获得正确的操作系统版本。

os.path 模块中的常用函数包括:

  • basename(path),用于获得给定路径的叶名称
  • dirname(path),用于获得文件路径的目录部分;它由 split(path) 函数加以补充,后者返回包含隔开的目录部分和文件部分的字节组
  • exists(path),用于查看路径下是否存在文件,针对无法解析的符号链接返回 False
  • getsize(path),用于快速查看路径下的字节数
  • isfile(path) 和 isdir(path),用于解析路径类型


虽然目前为止我们已经了解了一些丰富的文件系统浏览功能,但我们也只是初涉皮毛,因为还有多个其他模块。例如,filecmp 模块既能够比较文件又能够比较目录,tempfile 可以轻松地管理临时文件,glob 解析符合 Unix 式模式的文件路径(如在 ora_pmon_*.trc、log_*.xml 中,等等),非常有用的 shutil 模块实现高级文件系统操作,如复制和删除多个文件或整个文件树。 

与进程通信


os 模块并不仅限于文件管理。还可以用来与系统进程交互和生成系统进程,以及执行系统 kill 和 nice 调用。下表列出了最有用的进程管理函数。这些函数只对 Unix 和 Linux 平台有效,但在 Python 3.2 分支中正在进行一些工作以使这些函数可用于 Windows。 

函数

作用

os.abort()

向当前 Python 进程发送 SIGABRT

os.exec*(patharg1...argN,environ)

exec* 函数系列,用于以 path 指定的进程取代当前进程,可选择提供命令行参数和环境变量

os.kill(pidsignal)

向给定 pid 发送 signal

os.nice(value)

更改当前进程的 nice 值

os.popen(commandmode,buffersize)

对给定 command 打开一个未命名管道,有效地实现与进程的进一步交互;mode 表示管道打开处理属性(默认为“r”,表示读取)

os.spawn*(modepath,environ)

在一个新的进程中运行 path 下的程序(这些函数现在已被 subprocess 模块弃用)

os.system(command)

此函数通过操作系统 system() 调用(该调用可用于 Unix 和 Windows)运行由 command 定义的新进程



虽然其中许多函数可能在较旧的 Python 版本中派上用场,但从版本 2.4 开始,专门创建了一个专用的 subprocess 模块来管理进程。这个新模块最初在 2003 年提交到 Python 增强建议索引 (PEP),现在成为与系统进程通信的首选方法。

Subprocess 以简单、可用并且相当通用的接口取代 os.popen、os.spawn* 和 os.system 函数。清单 2 显示了 ps.py 程序的代码,此程序执行 ps aux 命令并将结果移到 Python 字典中。这里使用了一个管道来作为 stdout 的目标以捕获所有信息,并阻止输出到屏幕。

清单 2. ps.py:将系统进程映射移到 Python 字典中
import re
import subprocess

args = ['ps', 'aux']
ps = subprocess.Popen(args, stdout=subprocess.PIPE)
processes = ps.stdout.readlines()
header = re.split('\s+', processes.pop(0))[:-1]
header.remove('COMMAND')

PS = {}
for process in processes:
  columns = re.split('\s+', process)
  if columns[0]!='oracle':
       continue
  PS[int(columns[1])] = {}
  for position, column in enumerate(columns[:9]):
       PS[int(columns[1])][header[position].lower()] = column
       PS[int(columns[1])]['command'] = ' '.join(columns[10:])

from pprint import pprint
pprint(PS)


输出如下:

...
 25892: {'%cpu': '0.0',
       '%mem': '3.9',
       'command': 'xe_w000_XE ',
       'pid': '25892',
       'rss': '23672',
       'start': '16:02',
       'stat': 'Ss',
       'tty': '?',
       'user': 'oracle',
       'vsz': '457240'},
 26142: {'%cpu': '2.0',
       '%mem': '0.9',
       'command': 'python proc.py ',
       'pid': '26142',
       'rss': '5732',
       'start': '16:36',
       'stat': 'S+',
       'tty': 'pts/2',
       'user': 'oracle',
       'vsz': '160776'},
 26143: {'%cpu': '0.0',
       '%mem': '0.1',
       'command': 'ps aux ',
       'pid': '26143',
       'rss': '1100',
       'start': '16:36',
       'stat': 'R+',
       'tty': 'pts/2',
       'user': 'oracle',
       'vsz':'108044'}}

popen 函数接受多个关键字参数,如 stdin/stdout/stderr 描述符、用于设置进程工作目录的 cwd,或者设置子进程环境变量的 env。要查看命令的状态,只需查看 returncode 属性。进程标识符在 pid 属性下提供。

针对已创建进程的方法包括用于查看进程是否仍在运行的 poll()、用于在程序完成时进行恢复的 wait()、用于发送特定信号的 send_signal(),以及分别用于发送 SIGTERM 或 SIGKILL 信号的 terminate() 或 kill()。最后,要与生成的子进程完全交互,我们使用 communicate() 函数发送 stdin 输入。

为了对此进行说明,我们来创建一个基于遗留的 SYSDBA 连接而发展的简单 SQL*Plus 包装器。

清单 3. sp.py:通过 Python 与 SQL*Plus 进程通信
import os
from subprocess import Popen, PIPE

sqlplus = Popen(["sqlplus", "-S", "/", "as", "sysdba"], stdout=PIPE, stdin=PIPE)
sqlplus.stdin.write("select sysdate from dual;"+os.linesep)
sqlplus.stdin.write("select count(*) from all_objects;"+os.linesep)
out, err = sqlplus.communicate()
print out

This return output similar to:

SYSDATE
--------------
02-DEC-11

COUNT(*)
--------------
76147

报告服务

涉及走出数据库的一项最令人头疼的任务是发送警报或推送从数据仓库提取的经常性报告。好消息是,Python 不仅成功实现了一个全球流行的邮件列表系统 — Mailman,而且还提供一个丰富的电子邮件处理库,此库支持 MIME、附件、消息编码以及与电子邮件处理有关的各个方面。email 模块将协议本身内容与表示层相分离以便仅专注于构建邮件消息,而交付工作通过 smtplib 模块处理。

email.message 中的 Message 类代表用于处理电子邮件的核心类。email.mime 命名空间中的各个处理程序用于处理不同的附件类型。但在此示例中,我们将使用最通用的一个处理程序:email.mime.base 中的 MIMEBase。不过我们这方面略施小计,利用了电子表格软件将以表格格式打开 HTML 文件(如果它们具有 .xls 扩展名)的事实。我们还将利用 tempfile 模块的帮助。

Oracle Linux 并未预先安装 cx_Oracle 模块,因此您将需要从 cx-oracle.sourceforge.net 获得此模块。此外,为了能够导入 cx_Oracle 并使用网络配置文件,在启动 Python 解释器之前需要设置 ORACLE_HOME 和 LD_LIBRARY_PATH。 

[root@xe ~]# rpm -ivh cx_Oracle-5.1-11g-py26-1.x86_64.rpm
Preparing...########################################### [100%]
1:cx_Oracle ########################################### [100%]
[root@xe ~]# 
[root@xe ~]# su - oracle
[oracle@xe ~]$ export ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe
[oracle@xe ~]$ export LD_LIBRARY_PATH=$ORACLE_HOME/lib


请参见清单 4 了解完整程序,此程序连接到 Oracle Database 11g XE,提取员工数据,并将此数据打包为电子表格附件以便发送到电子邮件组。

清单 4. report.py:电子邮件报告服务

import cx_Oracle
import datetime
import smtplib
import tempfile
from email.message import Message
from email.encoders import encode_base64
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart

today = datetime.datetime.now()

msg = MIMEMultipart()
msg['From'] = 'Reports Service <reports@company.intranet>'
msg['To'] = 'receipients@company.intranet'
msg['Subject'] = 'Monthly employee report %d/%d ' % (today.month, today.year)

db = cx_Oracle.connect('hr', 'hrpwd', 'localhost/xe')
cursor = db.cursor()
cursor.execute("select * from employees order by 1")
report = tempfile.NamedTemporaryFile()
report.write("<table>")
for row in cursor:
  report.write("<tr>")
  for field in row:
    report.write("<td>%s</td>" % field)
  report.write("</tr>")
report.write("</table>")
report.flush()
cursor.close()
db.close()

attachment = MIMEBase('application', 'vnd.ms-excel')
report.file.seek(0)
attachment.set_payload(report.file.read())
encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment;filename=emp_report_%d_%d.xls' % (today.month, today.year))
msg.attach(attachment)

emailserver = smtplib.SMTP("localhost")
emailserver.sendmail(msg['From'], msg['To'], msg.as_string())
emailserver.quit()

如果我们更进一步采用此示例,可以使用 Python 图形处理库 (PIL) 获取统计图,附加存储在数据库中的 BLOB 的缩略图,或者借助 ReportLab 生成 PDF 报告以便发送到相关组。email 模块的功能非常强大,足以应对每种可能的情形。

总结

Python 丰富的跨平台模块库确实完善了 DBA 的技术组合,DBA 使用这些技术能够监视整个数据库体系、加快开发速度,同时保持极低的维护开销。Python 使用广泛,每个现代 Linux 平台都附带了这一工具,这可以进一步提高其采用率,并且随着时间的推移,有助于它成为可满足所有数据库管理需求的新的理想语言。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
MyBatis Generator(MBG)DB2使用说明 LONG VARCHAR 字段
DB2使用说明LONG VARCHAR 字段默认情况下,MyBatis Generator将LONG VARCHAR字段映射到java.lang.String数据类型,并将这些字段标记为jdbcType =“LONGVARCHAR”。
1267 0
SQL点滴17—使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识
   在开发过程中会遇到需要弄清楚这个数据库什么时候建的,这个数据库中有多少表,这个存储过程长的什么样子等等信息,今天把自己工作过程中经常用到的一些数据库引擎存储过程,系统视图等等总结一下以备不时之用。
763 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4623 0
【PROFILE】使用Oracle的PROFILE对用户资源限制和密码限制的研究与探索
1.用户创建语句PROFILE选项“引发的血案”如果大家细心的话,在创建用户的语法中有这么一个选项“PROFILE profile”。
749 0
安装SOA SUITE并使用ORACLE XE数据库作为组件要点.
使用高级安装, 在安装SOA SUITE前需要 1.设置ORACLE_HOME 和JAVA_HOME, JAVA要求1.4的, ORACLE_HOME指向为X:\oraclexe\app\oracle\product\10.
592 0
如何使用Oracle SQLDeveloper 中连接MS SQLServer和MySQL数据库
一、连接至MySQL数据库 1.下载mysql的jdbc驱动, http://dev.mysql.com/downloads/ 免费,嘿嘿。 2.解压zip文件(我下载的版本是mysql-connector-java-5.1.5),我们要用的是mysql-connector-java-5.1.5-bin.jar文件。
1031 0
+关注
385
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载