我 们 使 用PowerBuilder 编 程 时 总 是 会 大 量 的 用 到 数 据 库 的 查 询 语 句, 对 于 一条 复 杂 的 查 询 语 句 来 说, 对 相 同 的 查 询 条 件 的 实 现 一般 总 可 以 有 多 种 不 同 的 表 达 方 法, 而 不 同 的 表 达 会 使数 据 库 的 响 应 速 度 大 相 径 庭。 据 统 计, 约 有90% 性 能 问题 是 由 于 应 用 开 发 的 程 序 员 或 用 户 使 用 了 不 恰 当 的查 询 语 句 而 使 系 统 的 响 应 速 度 减 慢, 因 此 提 高 书 写SQL 语 句 的 质 量 对 软 件 性 能 的 提 高 有 很 大 关 系, 然 而 查 询语 句 的 好 坏 往 往 是 同 实 际 运 行 系 统 的 数 据 库 结 构、 记录 的 数 量 等 具 体 情 况 有 关 的, 我 们 无 法 只 用 几 条 简 单的 普 遍 适 用 的 规 律 来 总 结 应 当 怎 样 优 化 查 询 语 句, 以得 到 更 高 的 性 能。 不 过 我 们 首 先 应 当 对 数 据 库 管 理 系统 最 基 本 的 工 作 规 律 有 一 些 了 解, 这 样 才 能 使 我 们 在对 查 询 进 行 时 优 化 有 所 根 据。
由 于SQL 语 言是 面 向 结 果 而 不 是 面 向 过 程 的 查 询 语 言, 所 以 一 般 支持SQL 语 言 的 大 型 关 系 型 数 据 库 都 需 要 使 用 一 个 基 于 成本 的 优 化 器, 为 一 个 即 时 查 询 提 供 一 个 最 佳 的 执 行 策略。 对 于 优 化 器, 输 入 是 一 条 查 询 语 句, 输 出 是 一 个执 行 策 略。 这 个 执 行 策 略 是 执 行 这 个 查 询 所 需 要 的 一系 列 步 骤。 数 据 库 的 反 应 速 度 经 常 就 体 现 在 这 一 个 优化 算 法 上。 不 同 的 查 询 策 略 和 查 询 步 骤 可 使 得 服 务 器的 反 应 不 同, 因 此 采 用 适 当 的 查 询 策 略 可 使 得 系 统 性能 大 大 的 提 高。
优 化 器 的 优化 是 基 于 用 户 对 所 查 询 表 的 内 容 和 其 他 一 些 服 务 器的 有 关 因 素 如Cache 大 小、Cache 策 略、I/O 大 小 等。 一 般 来 说硬 盘 访 问 是 成 本 最 高 的 操 作, 因 此 对 用 户 来 讲, 使 优化 器 能 对 字 段 的 索 引 进 行 操 作 是 优 化 查 询 的 关 键。
SQL 查 询 语 句都 可 以 有 很 多 种 执 行 策 略, 优 化 器 将 估 计 出 全 部 的 执行 方 法 中 所 需 时 间 最 少 的 也 就 是 所 谓 成 本 最 低 的 那一 种 方 法。 一 般 来 讲, 最 为 重 要 的 选 择 就 是 使 用 什 么索 引 和 采 用 何 种 表 的 连 接 手 段, 而 所 有 优 化 的 进 行 都是 基 于 用 户 所 使 用 的 查 询 语 句 中 的where 子 句。
优 化 器 对where 子 句 中 的 优 化 分 为 以 下 几 类:
搜 索 参 数(searchargument)
搜 索 参 数 的核 心 就 是 数 据 库 能 否 使 用 表 中 字 段 的 索 引 来 查 询 数据, 而 不 必 直 接 查 询 记 录 中 的 数 据。 如 带 有=,<,>,>=,<= 等 操 作 符 的 条 件 系 统 就 可 以 直 接 使 用 索 引。
如 下 列 条 件 是 搜 索 参 数:
id = " T0001”salary > 30000a = 1 and c = 7而下列则不是搜索参数:salary = commissiondept != 10salary *12 >= 30000a = 1 or c = 7当然优化器有时可以将非搜索参数转化为搜索参数,如:SELECT name FROM employee WHERE salary BETWEEN $10000 AND $15000SELECT name FROM employee WHERE salary >= $10000 AND salary <= $15000 SELECT name FROM employee WHERE name like "a%" SELECT name FROM employee WHERE name>= "a" AND name<= "b" SELECT name FROM employee WHERE salary> $3000 * 12SELECT name FROM employee WHERE salary > $36000
因 此 我 们 在查 询 中 应 当 提 供 能 一 些 冗 余 的 搜 索 参 数, 使 优 化 器 有更 多 的 选 择 余 地, 如title 和titleauthor 两 张 表 是 一 对 多 的 关系, 同 样 的 查 询 条 件 我 们 有 以 下 三 种 表 现 方 法:
SELECT title_id, title FROM titles, titleauthorWHERE title.title_id = titleauthor.title_idAND titleauthor.title_id = 'T81002'SELECT title_id, title FROM titles, titleauthorWHERE title.title_id = titleauthor.title_idAND title.title_id = 'T81002'SELECT title_id, title FROM titles, titleauthorWHERE title.title_id = titleauthor.title_idAND title.title_id = 'T81002'AND titleauthor.title_id = 'T81002'
显 然 三 种 方法 一 种 比 一 种 要 好, 因 为 后 者 为 优 化 器 提 供 了 更 多 的选 择 机 会。
连 接 条 件
接 连 时 优 化器 将 所 有 连 接 的 方 法 全 部 列 举 出 来, 计 算 每 一 种 连 接的 成 本, 选 择 成 本 最 低 的 一 种。 如 连 接 时 用 到 的 数 据无 法 获 得, 一 般 系 统 会 使 用 平 均 密 度 作 为 依 据, 估 算可 能 的 命 中 率。 ' 或' 运 算 条 件
当 查 询 语 句中 有IN 这 样 的 关 键 词 时, 优 化 器 将 转 化 其 中 的 内 容 以OR 并 列 条 件。 例 如:
SELECT * FROM authorWHERE au_lname in ('Berry','Densham')将转化为:SELECT * FROM authorWHERE au_lname = 'Berry' or au_lname = 'Densham' 数 据 库 管 理系 统 将 对 每 一 个OR 从 句 进 行 查 询, 将 所 有 的 结 果 合 并后 去 除 重 复 项 作 为 最 终 结 果。
基 于 对 上 述数 据 库 优 化 器 的 了 解, 为 确 保 对 我 们 将 要 执 行 的 查 询语 句 得 以 进 行 准 确 的 优 化, 我 们 应 注 意 以 下 几 点:
1. 避 免 使 用不 兼 容 的 数 据 类 型。 例 如float 和int,char 和varchar,binary 和varbinary 是 不 兼 容 的。 数 据 类 型 的 不 兼 容 可 能 使 得 优 化 器 无 法执 行 一 些 本 来 可 以 进 行 的 优 化 操 作。 例 如:
SELECT name FROM employeeWHERE salary > 60000
在 这 条 语 句中, 如salary 字 段 是money 型 的, 则 优 化 器 很 难 对 其 进 行 优化, 因 为60000 是 个 整 型 数。 我 们 应 当 在 编 程 是 使 用 一 个函 数 将 整 型 数 转 化 成 为 钱 币 型 的 数, 而 不 要 等 到 运 行时 转 化。
2. 如 果 在 一个 存 储 过 程 或 触 发 器 中, 有 表 达 式 的 值 在 编 译 时 无 法得 到, 优 化 器 就 只 能 使 用 它 的 平 均 密 度 来 估 计 命 中 的记 录 数。 例 如:
DECLARE @value moneySELECT nameFROM employeeWHERE salary = @value
这 样 的 命 令是 可 优 化 的。 只 是 由 于@value 的 值 在 执 行 前 不 知 道, 它只 能 使 用 其 平 均 密 度, 来 估 计 这 条 命 令 将 要 命 中 的 记录 数。
3. 避 免 对 搜索 参 数 使 用 其 他 数 学 操 作 符。 如 要 将
SELECT name FROM employeeWHERE SUBSTRING(id, 1, 1) = 'B'SELECT name FROM emplyeeWHERE salary * 12 > 30000写成为:SELECT name FROM employeeWHERE id like 'B%'SELECT name FROM emplyeeWHERE salary > 3000
4. 避 免 使 用!= 或<> 等 这 样 的 操 作 符, 因 为 这 会 使 系 统 无 法 使 用 索 引,而 只 能 直 接 搜 索 表 中 的 数 据。 例 如:
SELECT id FROM employee
WHERE id != 'B%'
优 化 器 将 无法 通 过 索 引 来 确 定 将 要 命 中 的 行 数。
上 述 我 们 提 到 的 是 一 些 基 本 的提 高 查 询 速 度 的 注 意 事 项, 但 是 在 更 多 的 情 况 下, 程序 员 往 往 需 要 反 复 地 试 验 比 较 不 同 的 语 句 以 得 到 最佳 的 方 案。 此 外 更 为 重 要 的 是 需 要 数 据 库 管 理 员 在 数据 库 的 服 务 器 一 端 调 整 数 据 库 管 理 系 统 的 参 数, 以 得到 更 快 的 响 应 性 能, 这 就 超 出 了 本 文 的 讨 论 范 围。