本文档介绍了 Oracle® 和 Cloud SQL for MySQL 之间的基本查询差异,以及 Oracle 中的功能与 Cloud SQL for MySQL 中的功能之间的对应关系。此外,还概述了 Cloud SQL for MySQL 的性能注意事项,以及分析和优化 Google Cloud 查询性能的方法。虽然本文档介绍了为 Cloud SQL for MySQL 优化存储过程和触发器的方法,但并没有介绍如何将 PL/SQL 代码转换为 MySQL 存储过程和函数。
将 Oracle 数据库查询转换为 Cloud SQL for MySQL 查询时,需要考虑某些 SQL 方言差异。此外,还有多个内置函数在两个数据库平台之间不同或不兼容。
基本查询差异
虽然 Oracle 和 Cloud SQL for MySQL 均支持 ANSI SQL,但在查询数据时存在一些基本差异,主要是系统函数的使用。
下表重点介绍了 Oracle 和 Cloud SQL for MySQL 的 SELECT
和 FROM
语法之间的差异。
Oracle 功能名称 | Oracle 实现 | Cloud SQL for MySQL 支持 | Cloud SQL for MySQL 等效函数 |
---|---|---|---|
用于数据检索的 SQL 基本语法 |
SELECT FROM WHERE GROUP BY HAVING ORDER BY
|
是 |
SELECT FROM WHERE GROUP BY HAVING ORDER BY
|
SELECT (用于显示输出内容) |
SELECT 1 FROM DUAL
|
是 |
SELECT 1 或 SELECT 1 FROM DUAL
|
列别名 | SELECT COL1 AS C1
|
是 |
SELECT COL1 AS C1 或 SELECT COL1 C1
|
表名称区分大小写 | 不区分大小写(例如,表名称可以是 orders 和 ORDERS ) |
否 | 根据定义的表名称,区分大小写(例如,表名称只能是 orders 或 ORDERS ) |
内嵌视图
内嵌视图(也称为“派生表”)是 SELECT
语句,位于 FROM
子句中且用作子查询。内嵌视图可以通过移除复合计算或消除联接运算来帮助简化复杂查询,同时将多个单独的查询压缩为单个简化的查询。
下面举例说明了如何从 Oracle 11g/12c 内嵌视图转换到 Cloud SQL for MySQL。
Oracle 11g/12c 中的内嵌视图:
SELECT FIRST_NAME,
DEPARTMENT_ID,
SALARY,
DATE_COL
FROM EMPLOYEES,
(SELECT SYSDATE AS DATE_COL FROM DUAL);
Cloud SQL for MySQL 5.7 中使用别名的有效视图:
SELECT FIRST_NAME,
DEPARTMENT_ID,
SALARY,
DATE_COL
FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1;
联接
Cloud SQL for MySQL 支持 Oracle 的联接类型,但不支持 FULL JOIN
。Cloud SQL for MySQL 联接支持在 JOIN
语句中使用备用语法,例如 USING
子句、WHERE
子句(而不是 ON
子句)和 SUBQUERY
。
下表显示了 JOIN
转换示例。
Oracle JOIN 类型 |
Cloud SQL for MySQL 支持 | Cloud SQL for MySQL JOIN 语法
|
---|---|---|
INNER JOIN |
是 |
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
|
CROSS JOIN |
是 |
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E CROSS JOIN DEPARTMENTS D
|
FULL JOIN |
否 | 考虑将 UNION 与 LEFT 和
RIGHT JOINS:
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID
UNION
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E RIGHT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
搭配使用
|
LEFT JOIN
[ OUTER ]
|
是 |
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
|
RIGHT JOIN
[ OUTER ]
|
是 |
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E RIGHT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
|
SUBQUERY |
是 |
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E JOIN (SELECT * FROM DEPARTMENTS)D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
|
虽然 Cloud SQL for MySQL 同时支持 UNION
和 UNION ALL
函数,但不支持 Oracle 的 INTERSECT
和 MINUS
函数:
UNION
会在附加两个SELECT
语句的结果集之前消除重复记录。UNION ALL
会附加两个SELECT
语句的结果集,但不会消除重复记录。- 只要两个查询的结果集中都存在同一记录,
INTERSECT
就会返回两个SELECT
语句的交集。 MINUS
会比较两个或更多个SELECT
语句,仅返回第一个查询中未由第二个查询返回的不同行。
下表显示了一些从 Oracle 到 Cloud SQL for MySQL 的转换示例。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 支持 | Cloud SQL for MySQL 等效函数 |
---|---|---|---|
UNION |
SELECT COL1 FROM TBL1 UNION SELECT COL1 FROM TBL2
|
是 | SELECT COL1 FROM TBL1 UNION SELECT COL1 FROM TBL2
|
UNION ALL |
SELECT COL1 FROM TBL1 UNION ALL SELECT COL1 FROM TBL2
|
是 | SELECT COL1 FROM TBL1 UNION ALL SELECT COL1 FROM TBL2
|
INTERSECT |
SELECT COL1 FROM TBL1 INTERSECT SELECT COL1 FROM TBL2
|
否 |
SELECT COL1 FROM TBL1 WHERE COL1 IN (SELECT COL1 FROM TBL2)
|
MINUS |
SELECT COL1 FROM TBL1 MINUS SELECT COL1 FROM TBL2
|
否 | SELECT A.COL1
FROM TBL1 A LEFT JOIN TBL2 B
ON USING(COL1)
WHERE B.COL1 IS NULL
|
标量函数和组函数
Cloud SQL for MySQL 提供了一个详尽的标量(单行)和聚合函数列表。一些 Cloud SQL for MySQL 函数与其对应的 Oracle 函数类似(通过名称和功能,或使用不同的名称但功能类似)。虽然一些 Cloud SQL for MySQL 函数在名称上可以与其对应的 Oracle 函数相同,但它们也可以展示不同的功能。
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 字符函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
CONCAT |
返回与第二个字符串连接的第一个字符串:CONCAT('A', 1) = A1
|
是 | CONCAT |
CONCAT('A', 1) = A1 |
CONCAT USING PIPE |
FNAME |' '| LNAME |
否 | CONCAT |
CONCAT(FNAME, ' ', LNAME) |
LOWER 或 UPPER |
返回字符串,所有字母一律小写或一律大写:LOWER('SQL') = sql
|
是 | LOWER 或 UPPER |
LOWER('SQL') = sql |
LPAD/RPAD |
返回 expression1 ,它是在 expression2 中依字符顺序向左或向右填充 n 个字符后得到的结果:LPAD('A',3,'*') = **A
|
是 | LPAD 或 RPAD |
LPAD('A',3,'*') = **A |
SUBSTR |
返回字符串的一部分:从位置 x (在本例中为 3)开始,长度为 y 。字符串中的第一个位置是 1。
SUBSTR('MySQL', 3, 3)
= SQL
|
是 | SUBSTR |
SUBSTR('MySQL', 3, 3)
= SQL
|
INSTR |
返回某一字符串在给定字符串中的位置(索引):
INSTR('MySQL', 'y')
= 2
|
是 | INSTR |
INSTR('MySQL', 'y')
= 2
|
REPLACE |
返回给定字符串中出现的每一个搜索字符串均替换为替换字符串后的字符串:
REPLACE('ORADB', 'ORA', 'MySQL')
= MySQLDB
|
是 | REPLACE |
REPLACE('ORADB', 'ORA', 'MySQL')
= MySQLDB
|
TRIM |
去除字符串的开头或结尾字符(或两者):
TRIM(both '-' FROM '-MySQL-')
= MySQL
TRIM(' MySQL ')
= MySQL
|
是 | TRIM |
TRIM(both '-' FROM '-MySQL-')
= MySQL
TRIM(' MySQL ')
= MySQL
|
LTRIM/RTRIM |
从字符串的左侧或右侧移除搜索中出现的所有字符:
LTRIM(' MySQL', ' ')
= MySQL
|
部分 | LTRIM or RTRIM |
Oracle LTRIM 和 RTRIM 函数接受第二个参数,此参数指定要从字符串中移除的开头或结尾字符。Cloud SQL for MySQL 函数仅从给定字符串中移除开头和结尾空格:
LTRIM(' MySQL')
= MySQL
|
ASCII |
接受单个字符并返回其数字形式的 ASCII 码:ASCII('A') = 65
|
是 | ASCII |
ASCII('A') = 65 |
CHR |
返回 ASCII 码值(由介于 0-225 之间的数字值转换为字符):CHR(65) = A
|
需要不同的函数名称 | CHAR |
Cloud SQL for MySQL 使用 CHAR 函数实现相同的功能,因此您需要更改函数名称:CHAR(65) = A
|
LENGTH |
返回给定字符串的长度:LENGTH('MySQL') = 5
|
是 | LENGTH |
LENGTH('MySQL') = 5 |
REGEXP_REPLACE |
在字符串中搜索正则表达式模式:REGEXP_REPLACE('John', '[hn].', 'e') = Joe
|
否 | 不适用 | 从 MySQL 版本 8 开始支持。如需解决此问题,请尽可能使用 REPLACE 函数,或将逻辑移至应用层。 |
REGEXP_SUBSTR |
通过在字符串中搜索正则表达式模式来扩展 SUBSTR 函数的功能:
REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?')
=
https://console.cloud.google.com/
|
否 | 不适用 | 从 MySQL 版本 8 开始支持。如需解决此问题,请尽可能使用 SUBSTR 函数,或将逻辑移至应用层 |
REGEXP_COUNT |
返回模式在源字符串中出现的次数 | 否 | 不适用 | Cloud SQL for MySQL 没有等效函数可用。将此逻辑移至应用层。 |
REGEXP_INSTR |
在字符串位置(索引)中搜索正则表达式模式 | 否 | 不适用 | 从 MySQL 版本 8 开始支持。如果是使用旧版本,请将此逻辑移至应用层。 |
REVERSE |
返回给定字符串的倒序字符串:
REVERSE('MySQL')
= LQSyM
|
是 | REVERSE |
REVERSE('MySQL')
= LQSyM
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 数字函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
ABS |
返回给定数字的绝对值:ABS(-4.6) = 4.6 |
是 | ABS |
ABS(-4.6) = 4.6 |
CEIL |
返回大于或等于给定数字的最小整数:CEIL(21.4) = 22 |
是 | CEIL |
CEIL(21.4) = 22 |
FLOOR |
返回等于或小于给定数字的最大整数:FLOOR(-23.7) = -24
|
是 | FLOOR |
FLOOR(-23.7) = -24 |
MOD |
返回 m 除以 n 所得的余数:MOD(10, 3) = 1
|
是 | MOD |
MOD(10, 3) = 1 |
ROUND |
返回四舍五入到小数点右侧某一整数位的 n :ROUND(1.39, 1) = 1.4 |
是 | ROUND |
ROUND(1.39, 1) = 1.4 |
TRUNC (number) |
返回截断到 n2 个小数位的 n1 。第二个参数是可选的。
TRUNC(99.999) = 99
TRUNC(99.999, 0) = 99
|
需要不同的函数名称 | TRUNCATE (number) |
Cloud SQL for MySQL 函数具有不同的名称,第二个参数是必需参数。TRUNCATE(99.999, 0) = 99
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL datetime
函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
SYSDATE |
返回针对数据库服务器所在操作系统设置的当前日期和时间:
SELECT SYSDATE
FROM DUAL;
= 31-JUL-2019
|
是 | SYSDATE() |
Cloud SQL for MySQL
SELECT SYSDATE()
FROM DUAL;
= 2019-01-31 10:01:01.0
您可以在会话级更改 |
SYSTIMESTAMP |
返回系统日期,包括小数秒和时区:
SELECT SYSTIMESTAMP FROM DUAL
= 01-JAN-19 07.37.11.622187000 AM +00:00
|
需要不同的函数名称 |
CURRENT_
TIMESTAMP
|
默认情况下,Cloud SQL for MySQL 函数会返回不同的 datetime 格式。如需重新设置输出格式,请使用 DATE_FORMAT() 函数。
SELECT CURRENT_TIMESTAMP
FROM DUAL;
= 2019-01-31 06:55:07
|
LOCAL_
TIMESTAMP
|
将当前日期和时间返回为 TIMESTAMP 类型:
SELECT LOCALTIMESTAMP
FROM DUAL
= 01-JAN-19 10.01.10.123456 PM
|
返回不同的 datetime 格式 |
LOCAL_
TIMESTAMP
|
Cloud SQL for MySQL 函数返回与 Oracle 默认格式不同的 datetime 格式。如需重新设置输出格式,请使用 DATE_FORMAT() 函数。
SELECT LOCAL_TIMESTAMP
FROM DUAL
= 2019-01-01 10:01:01.0
|
CURRENT_DATE |
返回当前日期:
SELECT CURRENT_DATE
FROM DUAL
= 31-JAN-19
|
返回不同的 datetime 格式 |
CURRENT_
DATE
|
Cloud SQL for MySQL 函数返回不同的 datetime 格式。如需重新设置输出格式,请使用 DATE_FORMAT() 函数。
SELECT CURRENT_DATE
FROM DUAL
= 2019-01-31
|
CURRENT_
TIMESTAMP
|
返回当前日期和时间:
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 31-JAN-19 06.54.35.543146 AM +00:00
|
返回不同的 datetime 格式 |
CURRENT_
TIMESTAMP
|
Cloud SQL for MySQL 函数返回不同的 datetime 格式。如需重新设置输出格式,请使用 DATE_FORMAT() 函数。
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07
|
ADD_MONTHS |
返回日期加整数月数:
ADD_MONTHS(SYSDATE, 1)
= 31-JAN-19
|
需要不同的函数名称 | ADDDATE |
Cloud SQL for MySQL 函数返回不同的 datetime 格式。如需重新设置输出格式,请使用 DATE_FORMAT() 函数。
ADDDATE(SYSDATE(), 1)
= 2019-08-01 06:42:49.0
|
EXTRACT (日期部分) |
根据间隔表达式返回 datetime 字段的值:
EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
|
是 | EXTRACT (日期部分) |
EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
|
LAST_DAY |
返回给定日期的月份的最后一天:
LAST_DAY('01-JAN-2019')
= 31-JAN-19
|
部分 | LAST_DAY |
Cloud SQL for MySQL 函数返回与 Oracle 默认格式不同的 datetime 格式。如需重新设置输出格式,请使用 DATE_FORMAT() 函数。
LAST_DAY('2019-01-01')
= 2019-01-31
|
MONTH_
BETWEEN
|
返回给定日期 date1 和 date2 之间的月数:
MONTHS_BETWEEN(
SYSDATE, SYSDATE-60)
= 1.96
|
部分 |
PERIOD_DIFF
|
为计算月数之差值,Cloud SQL for MySQL PERIOD_DIFF 函数会计算两个时间段(格式为 YYMM 或 YYYYMM )的整数差值,然后返回此差值:
PERIOD_DIFF(
'201903', '201901')
= 2
|
TO_CHAR (Datetime) |
将数字、datetime 或时间戳类型转换为字符串类型
TO_CHAR(
SYSDATE,'DD-MM-YYYY HH24:MI:SS')
= 01-01-2019 10:01:01
|
需要不同的函数名称 | DATE_FORMAT |
Cloud SQL for MySQL DATE_FORMAT 函数会根据格式字符串设置日期值的格式:
DATE_FORMAT(
SYSDATE(),'%d-%m-%Y %H:%i:%s')
01-01-2019 10:01:01
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 编码和解码函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
DECODE |
使用 IF-THEN-ELSE 语句的功能将表达式与每个搜索值逐一进行比较 |
否 | CASE |
使用 Cloud SQL for MySQL CASE 语句实现类似功能 |
DUMP |
返回一个 VARCHAR2 值,此值包含表达式的数据类型代码、长度(字节数)和内部表示 |
否 | 不适用 | 不支持 |
ORA_HASH |
计算给定表达式的哈希值 | 否 | MD5 or SHA |
为 128 位校验和使用 MD5 函数,或者为 160 位校验和使用 SHA 函数 |
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 转换函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
CAST |
将一个内置数据类型或集合类型值转换为另一个内置数据类型或集合类型值:
CAST('1' as int) + 1
= 2
|
部分 | CAST |
根据是需要显式转换还是隐式转换,进行相应调整:
CAST('1' AS SIGNED) + 1
= 2
|
CONVERT |
将字符串从一个字符集转换为另一个字符集:
CONVERT (
'Ä Ê Í Õ Ø A B C D E ', 'US7ASCII', 'WE8ISO8859P1')
= ?? ?? ?? A B C
|
部分 | CONVERT |
Cloud SQL for MySQL CONVERT 函数需要对语法和参数进行一些调整:
CONVERT(
'Ä Ê Í A B C ' USING utf8)
= Ä Ê Í A B C
|
TO_CHAR (字符串/数字) |
该函数会将数字或日期转换为字符串:
TO_CHAR(22.73,'$99.9')
= $22.7
|
否 | FORMAT |
Cloud SQL for MySQL FORMAT 函数将数字转换为 #,###,###.## 等格式,将其舍入到某一小数位,然后以字符串形式返回结果:
CONCAT('$',
FORMAT(22.73, 1))
= $22.7
|
TO_DATE |
Oracle 的 TO_DATE 函数根据 datetimecode 格式将字符串转换为日期:
TO_DATE(
'2019/01/01', 'yyyy-mm-dd')
= 01-JAN-2019
|
需要不同的函数名称 | STR_TO_DATE |
Cloud SQL for MySQL STR_TO_DATE 函数接受一个字符串,并返回一个采用 datetime 格式的日期:
STR_TO_DATE(
'2019/01/01', '%Y/%m/%d')
= 2019-01-01
|
TO_NUMBER |
将表达式转换为 NUMBER 数据类型的值:
TO_NUMBER('01234')
= 1234
|
需要不同的函数名称 | CAST |
使用 Cloud SQL for MySQL CAST 函数返回与 Oracle TO_NUMBER 函数相同的结果:
CAST('01234' as SIGNED)
= 1234
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 条件式 SELECT
函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
CASE |
CASE 语句会从一系列条件中进行选择,并使用以下语法运行相应的语句:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
|
是 | CASE |
除了 CASE 函数之外,Cloud SQL for MySQL 还支持在 SELECT 语句中使用 IF/ELSE 条件式处理:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL null 函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
COALESCE |
返回表达式列表中的第一个非 null 表达式:
COALESCE(
null, '1', 'a')
= a
|
是 | COALESCE |
COALESCE(
null, '1', 'a')
= 1
|
NULLIF |
对 expression1 和 expression2 执行比较。如果它们相等,则函数会返回 null 。
如果它们不相等,则函数会返回 expression1 :
NULLIF('1', '2')
= a
|
是 | NULLIF |
NULLIF('1', '2')
= a
|
NVL |
将 null 值替换为查询结果中的字符串:
NVL(null, 'a')
= a
|
否 | IFNULL |
IFNULL(null, 'a')
= a
|
NVL2 |
根据表达式是 null 还是非 null 确定查询返回的值 | 否 | CASE |
CASE 语句会从一系列条件中进行选择,并运行相应的语句:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 环境和标识符函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
SYS_GUID |
生成并返回由 16 个字节组成的全局唯一标识符(RAW 值):
SELECT SYS_GUID()
FROM DUAL
=
8EFA4A31468B4C6DE05011AC0200009E
|
否 | REPLACE 和 UUID |
如需解决此问题,请使用 REPLACE 和 UUID 函数来模拟 SYS_GUID 函数:
REPLACE(
UUID(), '-', '')
|
UID |
返回一个整数,此整数可唯一标识会话用户(已登录的用户):
SELECT UID FROM DUAL
= 43
|
否 | 不适用 | 不适用 |
USER |
返回连接到当前会话的用户的用户名:
SELECT USER FROM DUAL
= username
|
是 | USER + INSTR + SUBSTR |
Cloud SQL for MySQL USER 函数返回连接的用户名和主机名 (root@IP_ADDRESS )。如需仅检索用户名,请使用其他支持函数:
SELECT
SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL
= root
|
USERENV |
返回有关当前 Oracle 会话的信息,例如会话的语言:
SELECT USERENV('LANGUAGE')
FROM DUAL
= ENGLISH_AMERICA.
AL32UTF8
|
否 |
SHOW SESSION
VARIABLES
|
Cloud SQL for MySQL SHOW SESSION VARIABLES 语句返回当前会话的设置:
SHOW SESSION VARIABLES LIKE '%collation%';
= utf8_general_ci
|
ROWID |
Oracle 会为表的每一行分配唯一的 ROWID ,以标识表中的行。ROWID 是数据对象编号、行的数据块、行位置以及数据文件所在行的地址。 |
部分 | 不适用 |
ROW_NUMBER() 是从 MySQL 8.0 开始提供。如果您使用的是早期版本,请使用会话变量 @row_number 模拟相同的功能。 |
ROWNUM |
返回一个数字,此数字表示 Oracle 表所返回行的顺序 | 部分 | 不适用 | ROW_NUMBER() 是从 MySQL 8.0 开始提供。如果您使用的是早期版本,请使用会话变量 @row_number 模拟相同的功能。 |
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 聚合(分组)函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
AVG |
返回列或表达式的平均值 | 是 | AVG |
等效于 Oracle |
COUNT
|
返回查询所返回的行数 | 是 | COUNT |
等效于 Oracle |
COUNT
(DISTINCT)
|
返回列或表达式中唯一值的数量 | 是 |
COUNT
(DISTINCT)
|
等效于 Oracle |
MAX |
返回列或表达式的最大值 | 是 | 等效于 Oracle | |
MIN |
返回列或表达式的最小值 | 是 | MIN |
等效于 Oracle |
SUM |
返回列或表达式的值的总和 | 是 | SUM |
等效于 Oracle |
LISTAGG |
对 ORDER BY 子句中指定的每个组中的数据进行排序,并连接测量列的值:
SELECT LISTAGG(
DEPARTMENT_NAME, ', ')
WITHIN GROUP
(ORDER BY DEPARTMENT_NAME) DEPT
FROM DEPARTMENTS;
-- Single line results
= Accounting, Administration, Benefits, Construction
|
需要不同的函数名称和语法 |
GROUP_
CONCAT
|
使用 Cloud SQL for MySQL GROUP_CONCAT 函数返回等效结果:
SELECT GROUP_CONCAT(
DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT
FROM DEPARTMENTS;
-- Single line results
= Accounting, Administration, Benefits, Construction
|
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 的等效 FETCH
函数。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 | Cloud SQL for MySQL 实现 |
---|---|---|---|---|
FETCH |
从多行查询的结果集中检索指定的行数:
SELECT * FROM
EMPLOYEES
FETCH FIRST 10 ROWS ONLY;
|
是 | LIMIT |
使用 MySQL LIMIT 子句从查询中检索行:
SELECT * FROM
EMPLOYEES
LIMIT 10;
|
基本过滤、运算符和子查询
基本过滤、运算符函数和子查询转换起来相对简单,只需要额定工作量。大部分工作都围绕转换日期格式进行,因为 Oracle 和 Cloud SQL for MySQL 使用不同的默认日期格式:
- Oracle
SYSDATE
函数默认返回以下格式:01-AUG-19
。 - Cloud SQL for MySQL
SYSDATE()
函数默认返回以下格式:2019-08-01 12:04:05
。
如需设置日期和时间格式,请使用 MySQL DATE_FORMAT
或 STR_TO_DATE
函数。
下表按名称和功能描述了 Oracle 和 Cloud SQL for MySQL 基本过滤、运算符和子查询函数等效的场景,以及建议转换的场景。
Oracle 函数 | Oracle 实现 | Cloud SQL for MySQL 等效函数 | Cloud SQL for MySQL 函数 |
---|---|---|---|
EXISTS/
NOT EXISTS
|
是 |
EXISTS/
NOT EXISTS
|
SELECT * FROM DEPARTMENTS D
WHERE EXISTS (SELECT 1
FROM EMPLOYEES E
WHERE
E.DEPARTMENT_ID =
D.DEPARTMENT_ID);
|
IN/NOT IN |
是 | IN/NOT IN |
SELECT * FROM DEPARTMENTS D
WHERE DEPARTMENT_ID IN
(SELECT DEPARTMENT_ID
FROM EMPLOYEES E);
-- OR
SELECT * FROM EMPLOYEES
WHERE (EMPLOYEE_ID, DEPARTMENT_ID)
IN((100, 90));
|
LIKE/NOT LIKE |
是 | LIKE/NOT LIKE |
SELECT * FROM EMPLOYEES
WHERE FIRST_NAME LIKE '_e_n%';
|
BETWEEN/
NOT BETWEEN
|
是 |
BETWEEN/
NOT BETWEEN
|
SELECT * FROM EMPLOYEES
WHERE EXTRACT(YEAR FROM HIRE_DATE)
NOT BETWEEN 2001 and 2004;
|
AND/OR |
是 | AND/OR |
SELECT * FROM EMPLOYEES
WHERE DEPARTMENT_ID IN(100, 101)
AND (SALARY >= 1000 OR HIRE_DATE <= '2006-02-05');
|
SubQuery |
是 | SubQuery |
Cloud SQL for MySQL 支持在 SELECT 子句和 JOIN 子句中使用子查询,以及支持在 WHERE/AND 子句中使用子查询进行过滤:
-- SELECT Subquery
SELECT D.DEPARTMENT_NAME,
(SELECT AVG(SALARY) AS AVG_SAL
FROM EMPLOYEES E
WHERE E.DEPARTMENT_ID =
D.DEPARTMENT_ID) AVG_SAL
FROM DEPARTMENTS D;
-- JOIN Subquery
SELECT FIRST_NAME, LAST_NAME, SALARY
FROM EMPLOYEES E JOIN
(SELECT *
FROM DEPARTMENTS
WHERE LOCATION_ID = 2700) D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
-- Filtering Subquery
SELECT FIRST_NAME,
LAST_NAME,
SALARY
FROM EMPLOYEES
WHERE SALARY < (SELECT AVG(SALARY)
FROM EMPLOYEES);
|
运算符 | 是 | 运算符 | Cloud SQL for MySQL 支持所有基本运算符:> | >= | < | <= | = | <> | !=
|
Cloud SQL for MySQL 查询的最佳做法
若要使 Cloud SQL for MySQL 和 Oracle 之间的性能水平相当,您可能需要优化查询。这些优化包括更改索引结构和调整数据库架构。本部分提供了一些指南,可帮助您在 Cloud SQL for MySQL 上实现水平相当的查询性能。
创建聚簇索引
使用 InnoDB 存储引擎时,最佳做法是使用主键定义表,因为此键会在该表上创建聚簇索引。除了改善查询性能之外,此方法还允许您创建其他二级索引。但您希望避免创建过多的索引。拥有多余索引不会改善性能,而且可能会降低 DML 的执行速度。使用这种最佳做法,会产生次优做法:定期监控多余索引,一旦有任何多余索引,就将其从数据库中删除。
使用以下查询来识别没有主键的表,以便您可以为其创建主键:
mysql> SELECT t.table_schema, t.table_name
FROM information_schema.tables t LEFT JOIN
information_schema.statistics s
ON t.table_schema=s.table_schema AND t.table_name=s.table_name
AND s.non_unique=0
WHERE s.table_name IS NULL
AND t.table_schema NOT IN('sys', 'information_schema', 'mysql',
'performance_schema')
AND t.`TABLE_TYPE` <> 'VIEW';
使用以下查询查找没有索引的表,以便您可以为其创建索引:
mysql> SELECT t.table_schema, t.table_name FROM INFORMATION_SCHEMA.tables t
WHERE table_name NOT IN
(SELECT table_name FROM (
SELECT table_name, index_name
FROM information_schema.statistics
GROUP BY table_name, index_name) tab_ind_cols
GROUP BY table_name)
AND table_schema NOT IN('sys', 'information_schema', 'mysql', 'performance_schema')
AND TABLE_TYPE <> 'VIEW';
使用以下查询检查是否有多余索引,以便您可以移除多余索引:
mysql> SELECT * FROM sys.schema_redundant_indexes;
调整查询参数
如需调整查询性能,您可能需要调整会话参数。Cloud SQL for MySQL 有一组标志,您可以针对此用途进行更改,包括以下标志:
- InnoDB 相关参数
SORT
个参数JOIN
个参数- 缓存处理参数
监控查询
运行缓慢的查询可能会导致系统停止响应或导致其他瓶颈,因此定期监控查询非常重要。
您可以通过以下几种方法诊断运行缓慢的 SQL 语句:
- 使用 Cloud SQL for MySQL 信息中心,获取有关运行缓慢查询的实时和历史数据分析。
- 使用 Cloud Monitoring 监控 Cloud SQL for MySQL 慢查询日志。
使用 Cloud SQL for MySQL
statement_analysis
视图查看有关 SQL 语句的运行时统计信息:mysql> SELECT * FROM sys.statement_analysis;
分析 Cloud SQL for MySQL 查询
Cloud SQL for MySQL 中的查询优化器会为 SELECT
、INSERT
、UPDATE
和 DELETE
语句生成执行计划。当您调整运行缓慢的查询时,这些计划非常有用。请牢记一些注意事项:
- 执行计划不是需要迁移的数据库对象;相反,它们是工具,用于分析 Oracle 和 Cloud SQL for MySQL 在针对相同数据集运行相同语句时的性能差异。
- Cloud SQL for MySQL 不支持与 Oracle 相同的执行计划语法、功能或输出。
以下示例计划说明了 Oracle 执行计划与 Cloud SQL for MySQL 执行计划之间的区别:
SQL> EXPLAIN PLAN FOR
SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105;
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY (FORMAT=>'ALL +OUTLINE'));
Plan hash value: 1833546154
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 69 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
mysql> EXPLAIN SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105;
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | EMPLOYEES | NULL | const | PRIMARY | PRIMARY | 3 | const | 1 | 100.00 | NULL |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
优化存储过程和触发器
与 Oracle 不同,Cloud SQL for MySQL 存储过程和函数会在每次执行时进行解析。对存储过程和函数性能进行基准化分析的实用工具是 MySQL BENCHMARK()
实用程序。此工具接受两个参数(一个迭代计数和一个表达式),并估算给定表达式(例如存储过程、函数和 SELECT
语句)的运行时间。输出表示所有迭代的大致总运行时间。
以下示例演示了 BENCHMARK()
实用程序:
-- SELECT Expression Example
mysql> select benchmark(10000000, 'select sysdate()');
+-----------------------------------------+
| benchmark(10000000, 'select sysdate()') |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
1 row in set (0.12 sec)
-- Result: Run time of 0.12 sec for 1,0000,000 iterations
-- FUNCTION Example
mysql> select benchmark(1000000, func1());
+-----------------------------+
| benchmark(1000000, func1()) |
+-----------------------------+
| 0 |
+-----------------------------+
1 row in set (2.54 sec)
-- Result: Run time of 2.54 sec for 1,000,000 iterations
如果您在转换期间中发现性能下降,请使用 MySQL EXPLAIN
命令确定可能导致性能下降的因素。解决性能缓慢问题的常见方案是更改表索引结构以适应 MySQL 优化器。另一种常见做法是减少不必要的数据检索或在程序化 MySQL 代码中使用临时表,以优化转换后的 PL/SQL 代码。
后续步骤
- 详细了解 MySQL 用户账号。
- 探索有关 Google Cloud 的参考架构、图表和最佳做法。查看我们的 Cloud 架构中心。