Два оператора SQL должны возвращать одинаковые результаты, но это не так (в AWS Aurora DB) - PullRequest
0 голосов
/ 04 мая 2019

Это определение таблицы для 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 - это UUID, который сохраняется как binary(16).

ThisКод 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 ]

1 голос
/ 04 мая 2019

Я вообще не вижу смысловой эквивалентности.

Тот, с exists проверяет, существует ли строка в другой таблице. Если такой подходящей строки не существует, то внешний запрос ничего не возвращает.

Это очень отличается от простого возвращения совпадающей строки в одной таблице.

Замечание о том, что два запроса возвращают одинаковые результаты для определенного набора данных, не делает их семантически эквивалентными. Должно быть гарантировано, что они будут возвращать одинаковые результаты для любых соответствующих данных для запроса. Например, 2 + 2 = 2 * 2, но это не делает сложение и умножение «семантически эквивалентными».

Я должен также добавить, что нетрудно обмануть оптимизаторы базы данных, даже если два выражения гарантированно эквивалентны.

0 голосов
/ 28 июня 2019

Таким образом, моя команда потратила буквально пару месяцев, пытаясь понять эту проблему и многие другие несоответствия (как, например, в этом сообщении), которые мы смогли воспроизвести на AWS Aurora DB 5.7, но не смогли воспроизвести на MySQL 5.7 или что-либо еще в этом отношении.

В рамках этих усилий мы задействовали поддержку AWS, которая была на удивление бесполезной. Они подтвердили, что могут воспроизвести несоответствия, выполнив те же запросы, которые мы выполняли в той же базе данных, что и мы, но затем сказали, что не могут скопировать эти данные в другую базу данных и все еще воспроизвести проблему, и это, похоже, удовлетворило их, чтобы отметить поддержку дело как решено. Теперь, конечно, это очень коварный дефект, поскольку его так сложно воспроизвести, и он настолько прерывистый и редкий, но когда он поражен, он становится надежно воспроизводимым в пределах затронутого набора данных. И как только вы обнаружите этот дефект, ваши приложения, зависящие от базы данных, больше не смогут корректно работать в этих уязвимых областях;)

Хотя мы не считаем, что дефект ограничен каскадным удалением, похоже, что способ «более надежного» создания этого дефекта состоит в удалении строк в таблицах с каскадным удалением. Опять же, это, кажется, производит дефект "более надежно", но даже тогда, это невероятно редко и трудно произвести. Однако мы могли бы создать его, запустив огромный автоматизированный набор тестов в тесном цикле. Опять же, как только вы действительно обнаружите этот дефект, затронутые данные будут надежно воспроизводить несоответствия - просто ОЧЕНЬ трудно устранить этот дефект.

Итак, какие выводы мы сделали в конце всего нашего анализа?

1) Во-первых, Торстен Кеттнер (см. Его опубликованный комментарий выше) является правильным - это дефект самого сервера RDBMS. У нас нет доступа к исходному коду AWS AuroraDB или к базовой инфраструктуре, и поэтому мы не можем устранить эту ошибку из-за какой-то более конкретной проблемы, но, возможно, это дефект сервера RDBMS, возможно, уровня персистентности данных и, возможно, где-то еще.

2) Исходя из (1) выше, мы решили, что AWS Amazon 5.7.x недостаточно совершенен для использования в рабочих приложениях. Несмотря на то, что он работает правильно в 99,9999% случаев, 0,0001% приводило к тому, что серверы баз данных разработки и производства совершали неправильные действия и возвращали неверные результаты, что для нас абсолютно неприемлемо. Мы также обнаружили случаи, когда ограничения целостности таблиц не были надежно соблюдены, что привело к появлению очень странных потерянных строк, которые должны были быть удалены как часть каскадного удаления в определении схемы, что опять-таки абсолютно неприемлемо для нас.

3) Нам не удалось воспроизвести любое из этих несоответствий в AWS MySQL 5.6, AWS MySQL 5.7, AWS AuroraDB с совместимостью с MySQL 5.6, не-AWS Windows MySQL 5.6 или не-AWS MySQL 5.7. Короче говоря, мы считаем, что все, что идет не так, характерно для AWS AuroraDB с совместимостью с MySQL 5.7. Мы провели обширное тестирование AWS AuroraDB, в частности, с совместимостью с MySQL 5.6, и не смогли воспроизвести ни одного из этих дефектов несоответствия, поэтому в настоящее время мы считаем, что AuroraDB с совместимостью с MySQL 5.6 является зрелым и пригодным для производственного использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...