Неявное преобразование типов: JSON_VALUE () против TRY_CAST (JSON_VALUE ()) - PullRequest
1 голос
/ 21 апреля 2019

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

Поэтому вместо создания нескольких таблиц с именем Link{SourceTableName} я создаю одну таблицу с GUIDдля представления идентификатора на нашей стороне и столбца NVARCHAR(MAX) для представления JSON, содержащего первичный ключ исходной таблицы.Я сохраняю первичный ключ как JSON, потому что должен поддерживать составные первичные ключи.Если мне нужны данные в исходной таблице, я могу JOIN столбец JSON с JSON_VALUE вместе с первичным ключом в исходной таблице.

Поскольку JSON_VALUE возвращает NVARCHAR(MAX), я будуполучить неявное преобразование типа, когда первичный ключ исходной таблицы не является NVARCHAR(MAX), что и следовало ожидать.Однако если я оберну это JSON_VALUE с TRY_CAST, то неявное преобразование больше не нужно.Я решил сделать это, но мне стало любопытно, произошла ли потеря производительности из-за дополнительного вызова функции.И вот тут все стало странным ...

Ниже приведено сравнение простого SELECT * в исходной таблице с SELECT * joined on TRY_CAST(JSON_VALUE()) против SELECT * joined on JSON_VALUE().

enter image description here enter image description here enter image description here

enter image description here

Я создал образец запросакоторый воспроизводит проблему.

CREATE TABLE [#Link] (
    [Id] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_Link_Id] DEFAULT(NEWID()),
    [LinkId] NVARCHAR(MAX) NOT NULL,
 CONSTRAINT [PK_Link] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY])
ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

CREATE TABLE [#Customer] (
    [Id] CHAR(7) NOT NULL,
    [Name] NVARCHAR(200) NULL,
 CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY])
ON [PRIMARY]

DECLARE @i INT = 0
WHILE @i < 20
BEGIN
    WITH seed AS (
        SELECT (@i * 32767) + 1 AS n
        UNION ALL
        SELECT n+1 FROM seed WHERE n+1<=(@i * 32767) + 32767
    )
    INSERT INTO
        [#Customer]
    SELECT
        RIGHT('0000000'+CAST([n] AS VARCHAR(7)),7)
        ,RIGHT('0000000'+CAST([n] AS VARCHAR(7)),7)
    FROM
        seed OPTION(maxrecursion 32767)
    SET @i = @i + 1
END

INSERT INTO
    [#Link] ([LinkId])
SELECT
    [value] FROM OPENJSON((SELECT [Id] FROM [#Customer] FOR JSON PATH))


SELECT TOP 10 *
FROM [#Customer]

SELECT TOP 10 *
FROM [#Customer]
JOIN [#Link] ON [#Customer].[Id] = TRY_CAST(JSON_VALUE([#Link].[LinkId], '$.Id') AS char(7))

SELECT TOP 10 *
FROM [#Customer]
JOIN [#Link] ON [#Customer].[Id] = JSON_VALUE([#Link].[LinkId], '$.Id')

SELECT TOP 100 *
FROM [#Customer]

SELECT TOP 100 *
FROM [#Customer]
JOIN [#Link] ON [#Customer].[Id] = TRY_CAST(JSON_VALUE([#Link].[LinkId], '$.Id') AS char(7))

SELECT TOP 100 *
FROM [#Customer]
JOIN [#Link] ON [#Customer].[Id] = JSON_VALUE([#Link].[LinkId], '$.Id')

DROP TABLE [#Customer]
DROP TABLE [#Link]

enter image description here enter image description here

Как вы можете видеть, есть разница между планом выполненияпервого JSON_VALUE() запроса и второго JSON_VALUE() запроса.Я не герой в расшифровке планов выполнения, но интересен только факт, что есть разница.

Присутствует предупреждение с жалобой на неявное преобразование типов, присутствующее в обоих планах выполнения.Это должно быть причиной различий в планах выполнения, потому что при изменении типа данных [#Customer].[Id] на NVARCHAR (7) планы выполнения TOP 10 и TOP 100 остаются прежними.

Я знаючто CONVERT_IMPLICIT снижает производительность, но я бы не ожидал увидеть разницу между TOP 10 и TOP 100. Поскольку второй запрос быстрее первого, очевидно, что первый может быть быстрее.Почему оптимизатор запросов не всегда выбирает второй план выполнения или я слишком много спрашиваю?

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