两个SQL语句应返回相同的结果,但不返回相同的结果(在AWS Aurora DB上)

时间:2019-05-04 18:11:59

标签: sql amazon-rds-aurora

这是GpsPosition的表定义:

CREATE TABLE GpsPosition 
(
    altitudeInMeters SMALLINT NOT NULL,
    dateCreated      BIGINT NOT NULL,
    dateRegistered   BIGINT NOT NULL,
    deviceId         BINARY(16) NOT NULL,
    emergencyId      BINARY(16) NULL,
    gpsFix           SMALLINT NOT NULL,
    heading          SMALLINT NOT NULL,
    horizontalUncertaintyInMeters SMALLINT NOT NULL,
    id               BINARY(16) NOT NULL,
    latestForDevice  BOOLEAN NOT NULL,
    latestForUser    BOOLEAN NOT NULL,
    latitude         DOUBLE PRECISION NOT NULL,
    longitude        DOUBLE PRECISION NOT NULL,
    numSatellites    SMALLINT NOT NULL,
    speedInKmph      SMALLINT NOT NULL,
    stale            BOOLEAN NOT NULL,
    userId           BINARY(16) NULL,
    verticalUncertaintyInMeters SMALLINT NOT NULL,

    PRIMARY KEY (id)
);

ALTER TABLE GpsPosition 
    ADD CONSTRAINT GpsPosition_deviceId_fkey 
        FOREIGN KEY (deviceId) REFERENCES Device(id) 
            ON UPDATE CASCADE ON DELETE CASCADE;

ALTER TABLE GpsPosition 
    ADD CONSTRAINT GpsPosition_emergencyId_fkey 
        FOREIGN KEY (emergencyId) REFERENCES Emergency(id) 
            ON UPDATE CASCADE ON DELETE SET NULL;

ALTER TABLE GpsPosition 
    ADD CONSTRAINT GpsPosition_userId_fkey 
        FOREIGN KEY (userId) REFERENCES User(id) 
            ON UPDATE CASCADE ON DELETE SET NULL;

ALTER TABLE GpsPosition 
    ADD CONSTRAINT deviceId_dateCreated_must_be_unique 
        UNIQUE (deviceId, dateCreated);

CREATE INDEX i2915035553 ON GpsPosition (deviceId);
CREATE INDEX deviceId_latestForDevice_is_non_unique ON GpsPosition (deviceId, latestForDevice);
CREATE INDEX i3210815937 ON GpsPosition (emergencyId);
CREATE INDEX i1689669068 ON GpsPosition (userId);
CREATE INDEX userId_latestForUser_is_non_unique ON GpsPosition (userId, latestForUser);

请注意,userId中的GpsPosition是一个存储为binary(16)的UUID。

此SQL代码正在AWS AuroraDB引擎5.7.12版上执行。

我希望下面的查询返回相同的结果,但是第一个返回许多结果,第二个不返回结果。知道为什么吗?

select *
from GpsPosition
where exists (select *
              from User
              where id = GpsPosition.userId and
                    id = UNHEX( '3f4163aab2ac46d6ad15164222aca89e' )
             );

select *
from GpsPosition
where userId = UNHEX( '3f4163aab2ac46d6ad15164222aca89e' );

请注意,下面的SQL语句按预期返回单行:

select *
from User 
where id = UNHEX( '3f4163aab2ac46d6ad15164222aca89e' );

2 个答案:

答案 0 :(得分:1)

我完全看不到语义对等。

带有exists的那个正在检查另一个表中是否存在一行。如果不存在这样的匹配行,则外部查询将不返回任何内容。

这与仅在单个表中返回匹配的行非常不同。

关于两个查询在特定数据集上返回相同结果的观察并不能使它们在语义上等效。必须保证他们在任何适当的数据上为查询返回相同的结果。例如2 + 2 = 2 * 2,但这不会使加法和乘法“在语义上等效”。

我还应该补充一点,即使保证两个表达式是等效的,也不难愚弄数据库优化器。

答案 1 :(得分:0)

因此,我们的团队实际上花了几个月的时间来尝试理解此问题和许多其他不一致之处(例如本帖子中的这一点),我们能够在AWS Aurora DB 5.7上重现,但无法在MySQL 5.7或其他任何方式上重现对于这个问题。

作为这项工作的一部分,我们使用了AWS支持,这显然无济于事。他们确认可以通过在相同的数据库上执行相同的查询来重现不一致之处,但随后表示他们无法将该数据复制到另一个数据库中并仍然重现该问题,这似乎使他们满意,以标记支持案情解决。现在可以肯定,这是一个非常隐蔽的缺陷,因为它很难复制,而且断断续续且罕见,但是一旦被击中,它就可以在受影响的数据集中可靠地再现。一旦确实解决了此缺陷,那么,取决于数据库的应用程序将无法在那些受影响的区域中正确运行;)

虽然我们不认为缺陷仅限于级联删除,但似乎“更可靠地”产生此缺陷的一种方法是删除具有级联删除的表中的行。同样,这似乎“更可靠地”产生了缺陷,但是即使如此,它还是极为罕见且难以产生。我们可以通过紧密循环运行一个巨大的自动化测试套件来生产它。同样,一旦您确实发现了此缺陷,受影响的数据将可靠地重现不一致的地方-很难修复此缺陷。

那么我们在所有分析结束时得出了什么结论?

1)首先,Thorsten Kettner(请参阅上面的发表评论)是正确的-这是RDBMS服务器本身的缺陷。我们无权访问AWS AuroraDB源代码或基础基础架构,因此我们无法从根本上将此缺陷引起,这是更具体的问题,但这可能是RDBMS服务器,数据持久层以及可能的缺陷。其他地方。

2)基于以上(1),我们认为AWS Amazon 5.7.x不够成熟,无法用于生产应用程序。即使它在99.9999%的时间内正常运行,但0.0001%的时间仍在导致开发和生产数据库服务器执行错误的操作并返回错误的结果,这对于我们来说绝对是不可接受的。我们还检测到无法可靠地遵守表完整性约束的情况,导致非常奇怪的孤立行应作为模式定义中级联删除的一部分删除,这对我们来说绝对是不可接受的。

3)我们无法在AWS MySQL 5.6,AWS MySQL 5.7,具有MySQL 5.6兼容性的AWS AuroraDB,非AWS Windows MySQL 5.6或非AWS MySQL 5.7上重现这些不一致之处。简而言之,我们认为出了什么问题是针对具有MySQL 5.7兼容性的AWS AuroraDB。我们特别在具有MySQL 5.6兼容性的AWS AuroraDB上进行了广泛的测试,并且无法重现这些不一致的缺陷,因此我们相信目前具有MySQL 5.6兼容性的AuroraDB已经成熟并且适合生产使用。