Странное поведение сервера MS SQL / проблемы с производительностью - PullRequest
0 голосов
/ 04 августа 2020

У меня странное поведение во время ответа на очень простой запрос. Все исследования до сих пор не показали никакой помощи или даже подсказки, что здесь могло быть не так.

У меня есть таблица в моей базе данных, которая используется для хранения цепочек подписанных объектов. У меня разные цепочки, и помимо подписываемых данных есть поля метаданных. Упрощенный оператор CREATE выглядит так:

CREATE TABLE [dbo].[SomeTable](
    [id] [bigint] NOT NULL,
    [user] [nvarchar](255) NULL,
    [someType] [nvarchar](255) NULL,
    [someId] [bigint] NULL,
    [someDescription] [nvarchar](255) NULL,
    [processName] [nvarchar](255) NULL,
    [taskId] [nvarchar](255) NULL,
    [data] [varbinary](max) NULL,
    [signature] [varbinary](max) NULL,
    [signedFormat] [nvarchar](255) NULL,
    [keyVersion] [int] NULL,
    [predecessorId] [bigint] NULL,
    [chainName] [nvarchar](255) NULL,
    [date] [bigint] NULL,
 CONSTRAINT [PK_SomeTable] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Конечно, есть ИНДЕКСЫ:

  • Первичный ключ - id
  • One AS C и один DES C на 'date'
  • Один на 'chainname'
  • Один на 'someDescription'
  • Один на 'someId'

все неуникальные, некластеризованные, кроме, конечно, первичного.

Между тем, эта таблица стала довольно большой - ну, по крайней мере, относительно. Полная база данных имеет размер около 100 ГБ, и эта таблица занимает половину ее. Индекс-пространство уже выросло до 7,5 ГБ. Статистика индекса актуальна.

Я пишу в эту таблицу, используя многопоточное Java -приложение, имеющее (Hikari-) JDB C -ConnectionPool.

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

Стандартное поведение классов, инкапсулирующее доступ к этому table состоит в том, что при попытке добавить в нее другие записи он пытается выяснить, существует ли уже цепочка с заданным именем. Если это так, загружается последняя запись для продолжения цепочки, в противном случае создается новая. Этот объект используется для добавления дополнительных записей в эту цепочку.

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

В любом случае, такое же стандартное поведение применяется к моему использованию классов, поэтому приложение пытается найти последнюю запись не- существующая сеть. Это должно быть довольно быстро, так как в соответствующих столбцах есть индексы. Это выполняемый оператор:

select top(1) * from SomeTable s where s.chainName = '<someNotExistingName>' order by s.date, s.id desc

При выполнении этого оператора в консоли управления он выполняется очень быстро и возвращает пустой результат менее чем за секунду. При запуске каждый поток (10-15, в зависимости) запрашивает цепочку fre sh почти одновременно. Попытка смоделировать этот «одновременный доступ» с помощью консоли по-прежнему показывает быстрое время отклика.

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

Я отслеживал запуск приложения с помощью SQL Profiler, но я не мог найти «ошибочного» или виновного заявления. Может быть, я использую неправильную настройку для профилирования? Я записывал один сеанс с использованием шаблона по умолчанию, а другой - с использованием шаблона «Продолжительность».

У меня заканчиваются идеи, на что я должен смотреть, чтобы выяснить, что вызывает эту проблему. Но я замечаю, что по мере того, как стол становится больше, становится все хуже. Между тем, требуется до 3 часов (!!) ожидания возврата потока с доступной его цепочкой: (* ​​1041 *

отчаянно ищу подсказки!

С уважением, Андреас

1 Ответ

0 голосов
/ 04 августа 2020

Не могли бы вы попробовать следующий запрос, потому что ваш

запрос не может использовать какой-либо оператор поиска по индексу, оператор сканирования индекса будет читать все страницы индекса.

select top(1) * from SomeTable s where s.chainName = '<someNotExistingName>' order by s.date, s.id desc

Execution Plan However, the following query has more chances to use your indexes.

SELECT *
FROM(SELECT *, 
            ROW_NUMBER() OVER(
            ORDER BY s.date, 
                     s.id DESC) AS RowNr
     FROM SomeTable s
     WHERE s.chainName = '') AS TMP_TBL
WHERE RowNr = 1;

введите описание изображения здесь

...