我的公司让我为 Python ORM 完成 Oracle 的后端。我很惊讶 RDBMS 做事情的方式有多么不同,即使是简单的东西。我学到了很多关于 Oracle 和其他 RDBMS 之间差异的知识。纯粹出于好奇,我想了解更多。
在将 SQL 从一个平台移植到另一个平台方面,有哪些常见的“陷阱”?
请,每个答案只有一个陷阱。
我的公司让我为 Python ORM 完成 Oracle 的后端。我很惊讶 RDBMS 做事情的方式有多么不同,即使是简单的东西。我学到了很多关于 Oracle 和其他 RDBMS 之间差异的知识。纯粹出于好奇,我想了解更多。
在将 SQL 从一个平台移植到另一个平台方面,有哪些常见的“陷阱”?
请,每个答案只有一个陷阱。
Oracle 似乎没有游标的问题,它们在 SQL Server 中是一个巨大的性能问题。
实际上,几乎所有性能调整都是特定于数据库的(这就是为什么 ANSII 标准代码与设计成特定于数据库的特定 SQL 风格的更好方法相比通常执行得非常差的原因)。
日期是另一件事,似乎从数据库到数据库的处理方式非常不同。
数据类型也不等价。倾向于让 SQL Server 新手的一件事是时间戳数据类型与日期和时间完全无关,并且不能转换为数据时间值。
Oracle 将不允许您插入空字符串:它们被默默地转换为 NULL。
Oracle 不允许选择没有 FROM 子句的语句。因此,您不能进行这样的查询:
SELECT 1
相反,您必须说查询来自DUAL
表:
SELECT 1 FROM DUAL
另一个例子是生成唯一(通常是代理)主键。
许多数据库,如 SQL Server 和 sqlite 允许将列声明为标识:通常,如果插入时缺少该列的值,数据库将为该列生成唯一值。
相比之下,Oracle 是否创建了一个与表分开的序列,然后在序列上使用 nextval 来生成下一个值:
CREATE SEQUENCE test_seq;
SELECT test_seq.nextval FROM dual;
或者,更典型的是:
INSERT INTO foo(id, title) VALUES (test_seq.nextval, 'bar');
在将 SQL 从一个平台移植到另一个平台方面,有哪些常见的“陷阱”?
与通过将字典单词直接替换为短语来尝试翻译 from English
to相同。Russian
为你好和再见工作,但因为玛丽有一只小羊羔而对莎士比亚无话可说。
不同RDBMS
的有不同的文化,尽管有SQL
他们的名字。
例如,行限制。
在Oracle
:
WHERE rownum = 1
在SQL Server
:
SELECT TOP 1
在MySQL
和PostgreSQL
:
LIMIT 1
在DB2
:
SELECT * ... FETCH FIRST 1 ROW ONLY
四个不同的子句。
多值 IN 子句查询。我过去一直在 Oracle 上使用这些,并且惊讶地发现您不能在 SQL Server 中执行此操作。例如,这个查询:
SELECT * FROM mytable WHERE (col1, col2) IN ( SELECT col1, col2 FROM othertable )
Oracle 对引用的处理方式与 MySQL 不同。
MySQL: `object_name`, 'string', "string"
Oracle: "object_name", 'string'
此外,逃避是不同的。
MySQL: 'It\'s easy'
Oracle: 'It''s slightly confusing'
(请注意,要在 Oracle 中转义除引号之外的任何内容,您可以在查询中使用 ESCAPE 指令;SELECT * FROM testTable WHERE percent = '50\%' ESCAPE '\')
我记得一个让我完全措手不及的特殊 Oracle 问题。我不确定这是实例的配置还是默认设置,但我们在 IN 语句中不能有超过 1000 个元素。所以我们不得不欺骗它做想做的事:
SELECT Col1,Col2
FROM Table
WHERE Code IN (1,2,3,...,1000)
OR Code IN (1001,1002,1003,...,2000)
等等
丑陋,但它的工作。
(在有人指出子查询或内联视图的明显解决方案之前,查询是在完全不同的系统上生成的)
Oracle 不允许您在一个查询中进行多次插入。MySQL 允许这样做:
INSERT INTO test(id, name) VALUES (1, 'foo'),(2, 'bar');
性能问题是一个大问题。例如,根据 AFAIK,Oracle 中的视图几乎与表一样快。当我不得不使用 SQLServer 时,情况并非如此。这些视图有效地扼杀了性能,使相同的选择减慢了一个数量级或更多(直接从表中查询需要 0.5 秒,而使用视图可能需要一分钟)。它们的使用也有很多限制,例如并非所有 SQL 函数都可以在视图上使用。
请注意,这在 6 年前的 5-6 年是正确的,我不知道微软从那以后是否对此进行了改进。
晦涩的连接语法,如 Oracle 用于外连接的 (+) 语法。在我曾经工作过的一家公司,到处都在使用这种语法,而不是标准的 LEFT OUTER JOIN / LEFT JOIN 语法,这使得将一些东西移植到 MySQL 上非常痛苦。
临时表 - Oracle 与 SQL Server/MySQL。从 Oracle 过渡到 MS/MySQL,没问题。反过来,就有点不一样了。
对于产品特定陷阱的全局,您需要了解逻辑数据库设计和物理数据库设计之间的区别。
逻辑数据库设计主要与表的特性有关。表的特征包括列和约束。尽管表本身是物理的,但表设计通常可以从一个数据库系统移植到另一个数据库系统。某些数据类型的工作方式存在差异,语法也存在一些差异,例如是否可以在表名中使用下划线。但是一个好的逻辑设计应该从一个系统移植到另一个系统,只需进行微小的更改或没有更改。
物理数据库设计主要与表结构所依赖的基础设施的特性有关。几乎所有系统都支持索引,默认的索引类型是 B-tree,尽管它可能被称为别的东西。但从那时起,每个系统都有自己的物理特征,从一个系统到另一个系统可能完全不同。Oracle 的一个典型物理特性是表空间。与表空间密切相关的是表和表空间之间的映射。物理设计必须在系统特定的基础上进行。
除了您使用的 RDM 系统之外,您还需要在设计中考虑数据量、负载、响应时间要求以及磁盘等系统资源。好消息是,可以在不更改应用程序代码的情况下对物理设计进行大量更改。这称为物理数据独立性。这意味着在编写了一些应用程序代码并加载了一些数据之后,您可以在一定程度上自由地调整和调整物理设计。
您可能想查看一些有关数据库设计的书籍,以更深入地了解逻辑和物理设计以及它们之间的区别。一些受欢迎的作者是 CJ Date 和 Joe Celko。
设置运营商支持。
除了 UNION / UNION ALL 之外,跨数据库的集合运算符支持相当参差不齐。Oracle 和 SQL Server 支持其中的大多数,但 Oracle 支持 MINUS 操作以及等效的标准 EXCEPT DISTINCT 操作。AFIK,MySQL 仅支持 UNION(不支持 INTERSECT 或 EXCEPT)。
我不确定这在 Python 附带的驱动程序中是否正确,但在我使用的“可怕”版本中,如果结果集中的列对列中的所有值返回 NULL,则列本身不会返回结果集的结构。这可能(并且经常发生)导致无法在开发中复制的生产错误。
由于您要离开 Oracle,所以这不应该是一个问题,但是开发人员使用一个关键字来缓解我怀疑 MySQL 支持的这个“功能”。不过,我忘记了它是什么,谷歌也没有提供帮助。
不同的数据库处理二进制数据略有不同。例如,这将在 MySQL 下工作:
mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t SET c = 'z';
Query OK, 1 row affected (0.01 sec)
但是,Oracle 依赖这些值为十六进制的值:
SQL> CREATE TABLE t (c RAW(3));
Table created.
SQL> INSERT INTO t VALUES ('z');
INSERT INTO t VALUES ('z')
*
ERROR at line 1:
ORA-01465: invalid hex number
相反,我们必须将其转换为十六进制:
SQL> INSERT INTO t VALUES (rawtohex('z'));
1 row created.