SQL Фильтр запросов к серверу работает медленно - PullRequest
0 голосов
/ 29 марта 2020

Я боролся с этим некоторое время.

У меня есть база данных с тремя таблицами (каждая из которых имеет миллионы записей) следующим образом (для простоты удалены некоторые столбцы):

1.[Entity]
    [Id]                UNIQUEIDENTIFIER PK,
    [EntityLevel_Id]    UNIQUEIDENTIFIER NOT NULL FK [EntityLevel] ([Id])
2.[EntityData]
    [Id]                UNIQUEIDENTIFIER PK,
    [Entity_Id]         UNIQUEIDENTIFIER NOT NULL FK [Entity] ([Id]),
    [DataLanguage_Id]   UNIQUEIDENTIFIER NOT NULL FK [Language] ([Id]),
    [Code]              NVARCHAR (250) NOT NULL
3.[EntityLevel]
    [Id]                UNIQUEIDENTIFIER PK,
    [Sort]              INT NOT NULL

Существуют индексы следующим образом:

[IX_Entity_EntityLevelId] ON [Entity] ([EntityLevel_Id])
[IX_EntityData_EntityId] ON [EntityData] ([Entity_Id])
[IX_EntityData_DataLanguageId_Code] ON [EntityData] ([DataLanguage_Id], [Code])
[IX_EntityLevel_Sort] ON [EntityLevel] ([Sort])

Чтобы исключить вероятность медлительности из-за выбранных столбцов, я выбираю только фиксированное значение

Следующий запрос выполняется очень быстро (менее 1 секунды):

SELECT TOP 20
    1
FROM
    [Entity]
    INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
    INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
    [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'

Следующий запрос также выполняется очень быстро:

SELECT TOP 20
    1
FROM
    [Entity]
    INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
    INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
    [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
ORDER BY
    [EntityData].[Code] ASC

А также быстро выполняется следующее:

SELECT TOP 20
    1
FROM
    [Entity]
    INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
    INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
    [EntityLevel].[Sort] = 1

НО, следующий запрос выполняется ОЧЕНЬ МЕДЛЕННО (примерно 10 секунд):

SELECT TOP 20
    1
FROM
    [Entity]
    INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
    INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
    [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
    AND
    [EntityLevel].[Sort] = 1
ORDER BY
    [EntityData].[Code]

Я не знаю причину, и я не нашел способа применить больше индексов, чтобы запрос выполнялся быстрее

Любая помощь приветствуется!

Редактировать: также быстро выполняются следующие запросы:

SELECT TOP 20
    1
FROM
    [Entity]
    INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
    INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
    [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
    AND
    [EntityLevel].[Sort] = 1

И

SELECT TOP 20
    1
FROM
    [Entity]
    INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
    INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
    [EntityLevel].[Sort] = 1
ORDER BY
    [EntityData].[Code]

Проблема появляется только при заказе по двум фильтрам

Ответы [ 3 ]

0 голосов
/ 29 марта 2020

Ваш вопрос по поводу этого запроса:

SELECT TOP 20 1
FROM [Entity] JOIN
     [EntityData]
     ON [Entity].[Id] = [EntityData].[Entity_Id] JOIN
     [EntityLevel]
     ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265' AND
      [EntityLevel].[Sort] = 1
ORDER BY [EntityData].[Code];

Мне кажется, проблема в том, что SQL Сервер не может использовать индекс для сортировки. Вы можете обойти это, используя EXISTS:

SELECT TOP 20 1
FROM Entity e JOIN
     EntityData ed
     ON e.Id = ed.Entity_Id 
WHERE ed.DataLanguage_Id = 'B6930015-F177-4ED3-97B0-AAEF401F9265' AND          
      EXISTS (SELECT 1
              FROM EntityLevel el
              WHERE e.EntityLevel_Id = el.Id AND
                    el.Sort = 1
             )
ORDER BY ed.Code;

Для этой версии вам нужен индекс на EntityLevel(ID, Sort).

Это может разрешить механизм SQL, использующий индекс для сортировки (как это происходит в других случаях). Конечно, вы не можете выбрать какие-либо столбцы из EntityLevel - но ваши примеры запросов в любом случае не делают этого.

0 голосов
/ 31 марта 2020

Для всех, кого это беспокоит, это решение проблемы:

Оказалось, что при таком количестве строк требовалось время для поиска ключей и совпадения sh из-за различных индексы, поэтому решением было добавить следующий индекс, чтобы разрешить использование одного индекса в таблице для всех значений фильтра (и порядка по):

CREATE NONCLUSTERED INDEX [IX_EntityData_EntityId_DataLanguageId_IncCode] ON [EntityData] ([Entity_Id], [DataLanguage_Id]) INCLUDE ([Code])

Но так как я могу также фильтровать по коду в некоторых ситуации, а не только использовать порядок, поэтому я изменил индекс так:

CREATE NONCLUSTERED INDEX [IX_EntityData_EntityId_DataLanguageId_Code] ON [EntityData] ([Entity_Id], [DataLanguage_Id], [Code])
0 голосов
/ 29 марта 2020

Попробуйте индексы на

  1. [Entity] ([Id], [EntityLevel_Id]),
  2. [EntityData] ([DataLanguage_Id], [Entity_id], [Code]) и
  3. [EntityLevel] ([Sort], [Id]).

Поэкспериментируйте с порядок столбцов. Для 2. и 3. Я предположил, что [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265' и [EntityLevel].[Sort] = 1 в фильтре предложений WHERE больше, чем объединение. Но я не знаю данных, и это предположение может быть неверным.

...