开发人员:框架
Rails on Oracle 优化技巧作者:Luca Mearelli
学习在 Oracle 数据库上构建更有效的 Rails 应用程序的提示和技巧。2007 年 5 月发表 使用 Ruby on Rails 框架,开发由 Oracle 数据库支持的复杂系统相对容易,但是这种简易性并没有消除开发人员对优化数据模型和操作它的代码的需要。 本文面向在 Oracle 数据库上使用 Ruby on Rails 应用程序的开发人员,特别关注那些具有需要优化的活动应用程序的开发人员。您将了解哪些选项可以调整处理数据库连接的参数以便 Oracle 适配器提高应用程序性能,以及哪些选项可以获取有用的插件来跟踪活动应用程序的查询执行计划。您将构建一组简单的模型并查看其上的各种典型查询,从而探究如何提高它们的效率。 设置学习本文的前提条件是:正确安装并配置 Ruby on Rails 以便与 Oracle 数据库连接。Casimir Saternos 的“Oracle 上的 Ruby on Rails 常见问题解答”详细说明了该过程。(它相当容易。) 本文的所有示例都是在一个 Windows XP 计算机上编写和测试的,该计算机运行 Instant Rails 1.5 预览版 1,该预览版连接到安装在 Debian Linux 上的 Oracle 数据库 10g 特别版 (XE)。 在本文的其余部分中,我将创建基于 Rails“版”HR 模式的示例,该模式经过修改可以直接遵循通用的 Rail 规范(不同于使用 Rails 应用程序的标准 HR 模式,这在 Saternos 的“Rails 上的 HR 模式”中有所说明)。该选择因需要在 Oracle 数据库上显示标准 Rails 应用程序的行为而指定,而无需处理单个模式以将 HR 模式映射到 Rails 约定。(这确实是处理旧式模式的一个非常聪明的方式!) 在示例代码文件中,您将发现模式的完整移植和(yml 格式的)数据转储(可用于使用 Active Record 固定插件加载它们,该插件也包含在内)。(db/db_loading.rb 文件进行数据导入,可以使用脚本/运行程序执行)。 这 6 个表由正规 HR 模式所包含的完全相同的数据填充,但它们对一些列进行了修改。(例如,它们现在都使用将一个 id 列作为其主键的通用 Rails 约定。) 模型还会定义它们之间的关系;您可以在示例代码文件中查看这些模型的完整代码: class Country < ActiveRecord::Base belongs_to :region has_many :locations end class Department < ActiveRecord::Base belongs_to :manager, :class_name => "Employee", :foreign_key => "manager_id" belongs_to :location has_many :employees end class Employee < ActiveRecord::Base belongs_to :department belongs_to :manager, :class_name => "Employee", :foreign_key => "manager_id" belongs_to :job belongs_to :department has_many :managed_employees, :class_name => "Employee", :foreign_key => "manager_id" end class Job < ActiveRecord::Base has_many :employees end class Location < ActiveRecord::Base belongs_to :country has_many :department end class Region < ActiveRecord::Base has_many :country end 我们所有的测试将只靠与 Rails 控制台的连接以及通过模型方法以交互方式查询数据库(类似于我们在控制器中进行的操作)来进行: C:\Progetti\ArticoliROR\Oracle\project> ruby script\console Loading development environment. >> 第 1 部分:关于配置、光标和行基本配置现在,您已经配置了在 Oracle 数据库上运行 Rails 所需的所有前提条件,这样引导您的 Rails 应用程序只需打开提示窗口(终端、xterm 等)并键入: rails myapp 这将使您具有一个可以保留代码(模型、视图、控制器和测试)的主干应用程序。您需要自定义 config/database.yml 文件,以便为 Rails 使用的每个数据库通知框架基本信息。 每个项使用一个键标识,以通知系统当开发应用程序、运行测试或者以生产模式运行应用程序时是否使用特定信息。您甚至可以定义这三个标准以外的其他数据库连接,并在您的 Rails 应用程序中使用它们,但这个主题超出了本文的范围。 具有单独的数据库设置意味着,您可以在开发或测试数据库时修改值,并执行您的测试和测量而无需触及产品数据库。 以下是一个基本配置示例: development: adapter: oracle host: DEBIAN username: rails password: rails adapter 参数指定,我们要连接一个 Oracle 数据库并选择 OracleAdapter(参见:activerecord/lib/active_record/connection_adapters/oracle_adapter.rb)。较早的 Rails 版本使用“oci”值标识 oracle 适配器,并且该值仍然可用。 通过 host 参数,您可以指定要连接的数据库。如果您为数据库配置了 TNS 项: DEBIAN = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.211.55.7)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE) ) ) 可以使用它的名称作为 host 参数;否则,可以使用 Easy Connect 命名约定为 Oracle 实例定址 (host://10.211.55.7:1521/XE)。 用户名和密码是您要用于应用程序的凭据。应用程序所需的所有对象(表、序列)应该允许该用户访问,而且在数据库移植过程中构建的所有内容将内置到该用户的模式中(至少这是默认行为)。 模型和 SQL 查询现在,我们将查看 ActiveRecord 生成的一些查询,并且仅当 Rails 以开发模式将所执行的所有查询写入日志文件的情况下才进行此操作。通过这种方式,您可以熟悉该框架的行为并了解该工具的功能。 我发现,在使用与数据进行复杂交互的强大框架时,需要深入了解框架代码如何将高级查询翻译成实际的 SQL。您将更好地了解应该使用的 Rails 编码以及如何编写更有效的代码。 获取模型数据的一个最常见的方式是按 id 查找对象: emp = Employee.find(202) 将获取 id = 202 的雇员记录。查看 development.log,我们将看到正在执行的查询: Employee Columns (0.120000) select column_name as name, data_type as sql_type, data_default, nullable, decode(data_type, 'NUMBER', data_precision, 'FLOAT', data_precision, 'VARCHAR2', data_length, null) as limit, decode(data_type, 'NUMBER', data_scale, null) as scale from all_tab_columns where owner = 'RAILS' and table_name = 'EMPLOYEES' order by column_id Employee Load (0.070000) SELECT * FROM employees WHERE (employees.id = 202) 第一个查询在模型类首次加载以从 employee 表提取列时执行,从而允许系统基于数据库结构为模型动态生成所需的方法。(这是使 Rails 开发真正快速的特性之一!)需要注意的是,当进行您的活动并以开发模式运行服务器时,您将看到此查询重复多次,这是因为模型会针对每个浏览器请求进行重新加载。这将使得服务器更慢,但您能够获取对数据库结构的更新而无需重启服务器。 第二个查询从 employees 表中为 id 是 202 的雇员获取数据。 模型的其他示例如下(都通过在数据库上执行的实际查询提供): 给定一个雇员,获知其部门经理。 mgr = emp.department.manager SELECT * FROM departments WHERE (departments.id = 20) SELECT * FROM employees WHERE (employees.id = 201)给定一个雇员,获知其部门的所有同事。 emps = emp.department.employees SELECT * FROM employees WHERE (employees.department_id = 20) mgr.managed_employees SELECT * FROM employees WHERE (employees.manager_id = 201) 您可以在单个查询中使用 include 选项从服务器以及与我们的实体有关系的对象进行下拉: emp = Employee.find(202, :include=>[:department,:manager]) emp.department emp.manager SELECT employees.id AS t0_r0, employees.commission AS t0_r1, employees.job_id AS t0_r2, employees.manager_id AS t0_r3,employees.salary AS t0_r4, employees.hire_date AS t0_r5, employees.phone_number AS t0_r6, employees.department_id AS t0_r7, employees.first_name AS t0_r8, employees.last_name AS t0_r9, employees.email AS t0_r10, departments.id AS t1_r0, departments.name AS t1_r1, departments.manager_id AS t1_r2, departments.location_id AS t1_r3, managers_employees.id AS t2_r0, managers_employees.commission AS t2_r1, managers_employees.job_id AS t2_r2, managers_employees.manager_id AS t2_r3, managers_employees.salary AS t2_r4, managers_employees.hire_date AS t2_r5, managers_employees.phone_number AS t2_r6, managers_employees.department_id AS t2_r7, managers_employees.first_name AS t2_r8, managers_employees.last_name AS t2_r9, managers_employees.email AS t2_r10 FROM employees LEFT OUTER JOIN departments ON departments.id = employees.department_id LEFT OUTER JOIN employees managers_employees ON managers_employees.id = employees.manager_id WHERE (employees.id = 202) 当使用行为类似于其他项组容器的对象时非常简便有效,因为它避免了针对您想操作的每一行使用查询进入数据库。 下面就是一个例子: job = Job.find(id,:include=>:employees) job.employees SELECT jobs.id AS t0_r0, jobs.job_title AS t0_r1, jobs.min_salary AS t0_r2, jobs.max_salary AS t0_r3, employees.id AS t1_r0, employees.commission AS t1_r1, employees.job_id AS t1_r2, employees.manager_id AS t1_r3, employees.salary AS t1_r4, employees.hire_date AS t1_r5, employees.phone_number AS t1_r6, employees.department_id AS t1_r7, employees.first_name AS t1_r8, employees.last_name AS t1_r9, employees.email AS t1_r10 FROM jobs LEFT OUTER JOIN employees ON employees.job_id = jobs.id WHERE (jobs.id = 7) 本文的目的之一是为您演示 1.2 版 Rails 中引入的新配置参数,它们可能有助于调整应用程序的数据库相关性能,但是在深入介绍之前,我要说明目前 Rails 如何构建实际使用的 SQL。 绑定变量和光标共享ActiveRecord 使用它的(动态生成的)模型和数据库知识动态地创建查询。它甚至以这种方式构建模型自身的大量方法,允许开发人员编写如下内容: Employee.find_by_first_name_and_last_name('Steven','King') 但是它通过将 SQL 查询构建为字符串,并在将查询发送到适配器进行执行之前通过参数插值来执行此操作(不使用绑定变量)。SQL 注入和安全问题会在引用 SQL 插值上的值时在适配器级别遭受攻击,除了影响性能外,还影响 Oracle 上运行的任何 Rails 应用程序的可伸缩性。要了解它如何影响性能和伸缩性,我将说明在执行查询时发生的情况。 当首次执行查询时,Oracle 执行硬分析步骤来验证它在语法上是正确的,而且所有访问的对象(表、列……)真实存在。如果检查通过,在库缓存中会创建一个新项,其中的分析结果可以在随后的执行中重用。库缓存的关键字是查询本身的 SQL 文本,因此有任何文字差异的两个查询对于分析来讲都被认为是不同的。 当执行新查询时,进行针对库缓存的散列查询以查看是否分析了此查询。如果发现了此查询,则使用缓存的分析结果并避免硬分析步骤,此外不向库缓存添加新项。最小化硬分析的方式是始终使用绑定参数。 在 1.2 版 之前的 Rails 应用程序的上下文中,如果不进行任何特定的数据库调整,则意味着每次执行不同的查询时(甚至区别仅在于参数值),该语句由数据库引擎进行硬分析而且新的查询项插入到库缓存中。 您可以通过查看 v$sql 视图(其中 sql_text 列保留用于查询的实际 SQL)验证发生了什么情况:v$sql 中的每行对应于库缓存中的一个项。我们可以使用以下查询获取我们的应用程序生成的所有查询(将我们限制为涉及 6 个表之一的查询): select sql_text from v$sql where ( lower(sql_text) like '%employee%' or lower(sql_text) like '%countries%' or lower(sql_text) like '%departments%' or lower(sql_text) like '%jobs%' or lower(sql_text) like '%locations%' or lower(sql_text) like '%regions%' ) and not lower(sql_text) like '%v$sql%' order by sql_text If we do the following: (1..200).each do |id| Employee.find(id) rescue nil end 它尝试获取 id 在 1 到 200 之间的每个雇员。您应该结束 v$sql 中的以下内容: SQL_TEXT -------------------------------------------------------------------------------- SELECT * FROM employees WHERE (employees.id = 1) SELECT * FROM employees WHERE (employees.id = 10) SELECT * FROM employees WHERE (employees.id = 100) SELECT * FROM employees WHERE (employees.id = 101) ... 这不是对一个预期伸缩的应用程序的建议行为,对于您可能在其中预期使用主键的大量查询的常见使用模式尤为如此(例如,访问用户表以进行登录或配置数据)。 所需的工作是为 Rails 提供正确的绑定变量处理,或至少让 ActiveRecord 适配器自身在查询中进行参数绑定。同时,最佳选项是使用该功能处理内置到数据库中的查询重写。 Oracle 提供的一个特定配置用于处理这种问题。CURSOR_SHARING 数据库参数更改数据库的行为方式,从而针对不使用绑定参数的查询进行软、硬分析。该参数可以设置为 exact、 similar 或 force(而后者可以设置为数据库范围或特定会话上)。
在 Rails 1.2 版之前,要更改光标共享设置,需要为整个数据库实例更改它或为 ActiveRecord 适配器打补丁。从上一主版本以来,已添加了适配器配置参数来进行此操作。 cursor_sharing 设置可用在 database.yml 中以选择首选值而不会混淆全局数据库参数(从而可以在其他应用程序可能需要不同设置的异类环境中成为更好的用户)。 development: adapter: oracle host: DEBIAN username: rails password: rails cursor_sharing: similar 它的值直接用在用于建立连接的 alter session 语句中(在 OracleConnectionFactory.new_connection 中): conn.exec "alter session set cursor_sharing = #{cursor_sharing}" rescue nil 此外,默认值已选择为 similar,这意味着无需将 cursor_sharing 添加到您获取合理行为的参数中:这些查询针对将取决于这些值的计划进行更改。 如果您重新进行上面的查询,您将在 v$sql 中看到这一点: SELECT * FROM employees WHERE (employees.id = :"SYS_B_0") just one library cache entry for any Employee.find(id) call. 要查看 similar 和 force 的影响,更新该表以具有一些固定的数据: Employee.find(:all).each do |emp| emp.salary = 3000 unless emp.id == 100 emp.save end 您更新了所有记录,使除 id 等于 100 之外的雇员具有 3,000 的工资。现在,您可以通过生成一个移植,从 Rails 项目将一个索引添加到 employee 表: C:\Progetti\ArticoliROR\Oracle\project>ruby script/generate migration AddIndexes exists db/migrate create db/migrate/007_add_indexes.rb 在生成的文件中,您应该具有 class AddIndexes < ActiveRecord::Migration def self.up add_index :employees, :salary, :name=>:idx_emp_salary end def self.down remove_index :employees, :name=>:idx_emp_salary end end then we do a rake db:migrate from the command line. Now if we do: Employee.find(:all, :conditions=>["salary = ?", 24000]) Employee.find(:all, :conditions=>["salary = ?", 3000]) 您会在 v$sql 中发现两个分析的项: SELECT * FROM employees WHERE (salary = :"SYS_B_0") SELECT * FROM employees WHERE (salary = :"SYS_B_0") 这是因为生成的这两个查询将根据工资值使用两个不同的计划。(在第一个示例中,将使用该索引,而在第二个示例中,完整的表扫描将是最佳计划。)使用 force 光标共享将通知数据库针对两个查询使用同一个分析的项,这并不是我们在本例中所希望看到的,即使它意味着只有一个缓存项。 Rails 中有一个配置可用于此处,让我们根据每个应用程序示例调整它的值,这也取决于您有哪种数据以及您希望您的应用程序采用哪些使用模式。 将第二个参数添加到 Rails 1.2(这可能有助于调整应用程序)是 prefetch_rows 配置。这允许设置 OCI_ATTR_PREFETCH_ROWS 连接参数,该参数指定在每个回程中从数据库预提取的行数。它可以在您想提取大量行的所有情况中极大地提高性能。 典型的模式是迭代通过一组实体,如下所示: Employee.find(:all, :conditions=>"salary < 5000") 在这些示例中,预提取行意味着较少访问数据库,尽管代价是适配器使用更多内存 — 如果您想处理查询返回的所有行,这无论如何都不是问题。 默认值设置为 100,该值已由 Oracle 适配器开发人员确定为在一定范围的测试示例中是理想的,但对于 cursor_sharing 来讲,需要以应用程序使用的实际数据集和查询调整预提取值。对于自定义调整,该参数通常在 database.yml 中设置: development: adapter: oracle host: DEBIAN username: rails password: rails prefetch_rows: 100 第 2 部分:执行计划和索引Rails 不能做什么?虽然 Rails 通过聪明地使用规范和设计模式实现大大减轻了开发负担,但在一些情况下,它没有所需的知识来为开发人员作出决策。因此,Rails 开发人员不应该忘记构建数据库支持的应用程序,而不是针对哪个数据库进行开发。 虽然多数编码以非常独立于数据库的方式工作,但如果您想使应用程序具有最佳性能,需要很好地了解数据库的工作方式。 在开发数据模型和构建查询时,了解数据库的工作方式很有用,但更重要的时候是确定您的表需要什么索引。这是框架无法做甚至不想尝试的事,因为它取决于:
此外,这些因素彼此影响,而且任何优化将取决于它们的整体。Jamis Buck 在他的博客“针对 DB 性能的索引”中给出了关于可能需要的索引种类的提示:
每个索引增加一些开销,因为它需要在数据插入和更新时进行更新,因此您不应该为每个列(或列组合)添加索引。您应该从一些合理的索引组开始进行明智的选择,随着应用程序的发展修改它们,考虑实际数据和使用模式。 解释计划。在一个 Oracle 上下文中,这意味着使用 explain plan 命令了解查询的执行方式。它为开发人员提供优化查询自身并最终添加索引的方式。 应该始终尝试首先优化查询,之后再添加索引。 Rails 通过 ActiveRecord 的简便的 find_by_sql 方法使得使用自定义查询(而非常规查询)相当容易。但是请注意,在 find_by_sql 调用中,您可以简单地传递 SQL 查询的文本,但是您实际上应该确认您使用参数替换表单传递查询数组和参数列表。通过这种方式,可以使用数据库适配器中的参数引用,而且您确保将来当 ActiveRecord 支持它们时您会使用实际绑定变量而无需修改您的代码。 Query_Analyzer 插件。在应用程序中查找瓶颈时,重要的是了解执行了哪些查询。Rails 日志文件在此处非常有用,因为应用程序在以开发模式运行时会记录所有实际查询。可能逐个收集并检查它们以发现查询并生成执行计划。这可能成为繁琐的工作。query_analyzer 插件通过在日志文件中转储解释计划有助于减轻此负担。您可以从此处获得一个 Oracle 兼容的版本;它最初是由 Bob Silva 为 MySQL 开发的。要安装它,只需在 Rails 项目的提供商/插件目录中解压缩存档内容即可。 要允许此插件在 Oracle 中工作,需要为数据库用户提供在加载模型时查询的数据字典表的足够权限。以下语句将进行此操作: GRANT SELECT ANY DICTIONARY TO < database user >; 该插件高手为数据库适配器打补丁,以便为运行于 INFO 之下的登录级的适配器执行的每个查询添加解释计划。该计划在调试级格式化并打印到默认日志程序。默认行为确保运行在生产环境中时不执行此计划。 有两个参数可用于修改默认行为;可以在环境设置文件中修改它们:plan_table_name 参数可用于指定 plan 表的名称,默认名是标准的 PLAN_TABLE;plan_details 参数用于指定哪些细节应该由解释计划语句打印。可能的值为:
如果您执行一个常见查询: Employee.find(101) 它会将以下数据转储到 development.log 文件: Employee Load (0.000000) explain plan for SELECT * FROM employees WHERE (employees.id = 101) Analyzing Employee Load plan_table_output ------------------------------------------------------------------------------------------- Plan hash value: 1171009080 ------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 719 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 719 | 2 (0)| 00:00:01 | |* 2 | INDEX UNIQUE SCAN | SYS_C004026 | 1 | | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEES"."ID"=101) 请注意,该查询使用与该表的主键相关的唯一索引;在本例中,无需进行任何操作。 使插件保持活动(设置调试级别的信息)使您能够在运行应用程序时为所有查询收集 plan 表输出。 该 plan 表输出大量关于查询的信息。您可以通过在日志文件中搜索‘TABLE ACCESS FULL’快速发现可能需要新索引的表。 Employee Load (0.010000) explain plan for SELECT * FROM employees WHERE (first_name = 'Stephen') Analyzing Employee Load plan_table_output ------------------------------------------------------------------------------- Plan hash value: 1445457117 ------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 719 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| EMPLOYEES | 1 | 719 | 3 (0)| 00:00:01 | ------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("FIRST_NAME"='Stephen') Note ----- - dynamic sampling used for this statement 这是查询名为‘Stephen’的所有雇员:Employee.find(:all, :conditions=>["first_name = ?", "Stephen"])。 请注意,该查询需要扫描完整的 EMPLOYEES 表,以便在 first_name 列上使用过滤器时只获取一行。如果通过应用程序多次看到这种查询,应该考虑添加索引。开销较大的操作的谓词信息可以在哪些索引可以受益于查询执行方面为您提供很好的提示 — 在本例中,显然是 first_name 列上的一个索引。 Rails 移植。可以使用 Rails 移植管理索引。(有关移植的内容以及如何用于管理数据库模式的详细信息,请参阅 API 文档。)要添加索引,使用: add_index table_name, column_names, options = {} 这会在“column_names”(可以是单列或列的列表)的“table_name”上添加索引: add_index :departments, :manager_id add_index :locations, [:city, :postal_code] 在 options 参数中,可以指定是否将索引创建为唯一的: add_index :locations, [:city, :postal_code, :street_address], :unique => true 或者提供一个给定名。(这在 Oracle 上是有用的,因为默认情况是使用表名和第一列名的组合,这未免太长了。) add_index :locations, [:city, :postal_code], :name => :idx_city_zip 要删除索引,只需使用 remove_index 方法: remove_index table_name, options = {} we can pass as options the column name(s) or the index name: remove_index :departments, :manager_id remove_index :departments, :column => :manager_id remove_index :locations, :column => [:city, :postal_code, :street_address] remove_index :locations, :name => :idx_city_zip 如果需要使用更复杂或数据库特定的 SQL,请从您将 SQL 字符串传递到的 up 或 down 方法使用 execute 命令来执行: execute "CREATE INDEX idx_emp_first_name ON employees (first_name)" 在上面的例子中: C:\Progetti\ArticoliROR\Oracle\project>ruby script/generate migration AddFirstNameIndex exists db/migrate create db/migrate/008_add_first_name_index.rb This is the migration file: class AddFirstNameIndex < ActiveRecord::Migration def self.up add_index :employees, :first_name, :name=>:idx_emp_first_name end def self.down remove_index :employees, :name=>:idx_emp_first_names end end 使用 rake db:migrate 运行移植。 C:\Progetti\ArticoliROR\Oracle\project>rake db:migrate (in C:/Progetti/ArticoliROR/Oracle/project) == AddFirstNameIndex: migrating =============================================== -- add_index(:employees, :first_name, {:name=>:idx_emp_first_name}) -> 0.0100s == AddFirstNameIndex: migrated (0.0100s) ====================================== 再次执行查询将显示此索引正在使用: Employee Load (0.010000) explain plan for SELECT * FROM employees WHERE (first_name = 'Stephen') Analyzing Employee Load plan_table_output -------------------------------------------------------------------------------------------------- Plan hash value: 2736374945 -------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 719 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 719 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_EMP_FIRST_NAME | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("FIRST_NAME"='Stephen') Note ----- - dynamic sampling used for this statement 正如您看到的,使用此插件查看运行中的应用程序使用的执行计划非常容易,而且您甚至可以将其安装在生产服务器上,并在需要时通过更改事件日志级别来禁用/启用它。 结论在本文中,您简单了解了如何在 Rails 应用程序中配置 Oracle 数据库连接,而且还看到了如何在 1.2 版本中更新框架,以便在使用 cursor_sharing 和 prefetch_rows 参数的整个过程中(在等待实际绑定变量实现时)获得更佳的性能。 您还可以检查与调整数据库(特别是创建/删除索引)相关的 Rails 移植命令。 最后,正如您学到的,可以很好地了解 Rails 通过代码构建 SQL 的方式以及数据库执行它们的方式,以便获得最佳性能。此处提供的插件应该有所帮助。 Luca Mearelli [http://spazidigitali.com] 是 Oracle 和 Web 技术专家,住在意大利的 Città di Castello。 将您的意见发送给我们 |