Хотя этот пост не будет полным ответом из-за недостатка информации, он должен быть в состоянии указать вам правильное направление или иным образом получить представление, которым вы впоследствии сможете поделиться с сообществом.
К сожалению, это определение приводит к снижению производительности по сравнению с предыдущей ситуацией с таблицей на основе диска. Порядок величины более или менее на 10% выше (что в некоторых случаях достигает 100%, поэтому удваивается).
Более того, я ожидал получить супер-преимущество в сценариях с высоким уровнем параллелизма, учитывая архитектуру без блокировок, рекламируемую Microsoft. Вместо этого наихудшие показатели происходят именно тогда, когда несколько таблиц одновременно выполняют несколько запросов к таблице.
Это беспокоит, поскольку это определенно не должно иметь место. Определенные рабочие нагрузки не предназначены для таблиц памяти (SQL 2014), и некоторые рабочие нагрузки поддаются ему. В большинстве ситуаций может быть минимальное снижение производительности, просто путем миграции и выбора правильных индексов.
Первоначально я думал очень узко о ваших вопросах относительно этого:
Вопросов:
- какой правильный BUCKET_COUNT установить?
- какой индекс я должен использовать?
- почему производительность хуже, чем с дисковой таблицей?
Первоначально я полагал, что есть проблема с фактической таблицей в памяти и индексами, не являющимися оптимальными. Хотя существуют некоторые проблемы с определением хеш-индекса, оптимизированного для памяти, я считаю, что реальная проблема связана с используемыми запросами.
-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
SELECT @fixedValue, id2, col1, col2 FROM AnotherTable
Эта вставка должна быть очень быстрой, если она задействует только таблицу в памяти. Это, однако, также включает таблицу на основе диска и подвергается всем блокировкам и блокировкам, связанным с этим. Таким образом, в реальном времени трата здесь на основе таблицы диска.
Когда я провел быструю проверку на 100 000 вставок строк из таблицы на основе диска после загрузки данных в память - это было время отклика менее секунды. Однако большая часть ваших данных хранится только в течение очень короткого промежутка времени, менее 20 секунд. Это не дает много времени, чтобы действительно жить в кеше. Кроме того, я не уверен, насколько велик на AnotherTable
самом деле, и не знаю, считываются ли значения с диска или нет. Мы должны положиться на вас за эти ответы.
С помощью запроса Выбрать:
SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1
Опять же, мы во власти производительности таблиц interop + disk. Кроме того, сортировки недешевы для индексов HASH, поэтому следует использовать некластеризованный индекс. Об этом говорится в руководстве по индексам, которое я привел в комментариях
Чтобы привести некоторые фактические факты, основанные на исследованиях, я загрузил SearchItems
в память таблицу с 10 миллионами строк и AnotherTable
100 000, поскольку я не знал ее фактического размера или статистики. Затем я использовал запрос select для выполнения. Кроме того, я создал расширенный сеанс событий в wait_completed и поместил его в кольцевой буфер. Это было убрано после каждого запуска. Я также побежал DBCC DROPCLEANBUFFERS
имитировать среду, в которой все данные могут быть не резидентными.
Результаты не были чем-то впечатляющим, если смотреть на них в вакууме. Так как ноутбук, на котором я тестирую этот компьютер, использует SSD более высокого класса, я искусственно уменьшил производительность диска для используемой виртуальной машины.
Результаты были получены без информации ожидания после 5 запусков запроса только по таблице в памяти (без объединения и без подзапросов). Это в значительной степени, как и ожидалось.
Однако при использовании исходного запроса у меня были ожидания. В данном случае это был PAGEIOLATCH_SH, который имеет смысл, когда данные считываются с диска. Поскольку я являюсь единственным пользователем в этой системе и не тратил время на создание обширной тестовой среды для вставок, обновлений, удалений для объединенной таблицы, я не ожидал, что какая-либо блокировка или блокировка вступят в силу.
В этом случае, опять же, значительная часть времени была потрачена на таблицу на основе диска.
Наконец запрос на удаление. Поиск строк, основанных только на ID1, не очень эффективен с индексом has. Хотя верно, что предикаты равенства - это то, для чего нужны хеш-индексы, область, в которую попадают данные, основана на целых хэшированных столбцах. Таким образом, id1, id2, где id1 = 1, id2 = 2 и id1 = 1, id2 = 3, будут хэшироваться в разные сегменты, поскольку хэш будет проходить через (1,2) и (1,3). Это не будет простым сканированием диапазона B-Tree, поскольку хеш-индексы структурированы не одинаково. Тогда я ожидал бы, что это не будет идеальным показателем для этой операции, однако я бы не ожидал, что это займет на несколько порядков больше, чем у опытных. Мне было бы интересно увидеть wait_info по этому вопросу.
Более того, я ожидал получить супер-преимущество в сценариях с высоким уровнем параллелизма, учитывая архитектуру без блокировок, рекламируемую Microsoft. Вместо этого наихудшие показатели происходят именно тогда, когда несколько таблиц одновременно выполняют несколько запросов к таблице.
Хотя верно, что блокировки используются для логической согласованности, операции все еще должны быть атомарными. Это делается с помощью специального оператора сравнения на основе ЦП (именно поэтому In-Memory работает только с некоторыми [хотя и почти всеми процессорами, изготовленными за последние 4 года]). Таким образом, мы не получаем все бесплатно, еще будет время для выполнения этих операций.
Еще один момент, о котором следует упомянуть, - это тот факт, что почти во всех запросах используется интерфейс T-SQL (а не компилируемый в естественном порядке SPROC), который затрагивает хотя бы одну таблицу на основе дисков. Вот почему я считаю, что, в конце концов, у нас фактически нет увеличения производительности, поскольку мы все еще ограничены производительностью таблиц на основе дисков.
Следовать за:
Создайте расширенный сеанс событий для wait_completed и укажите известный вам SPID. Запустите запрос и дайте нам вывод или используйте его для внутреннего использования.
Дайте нам обновленную информацию о выходе из # 1.
Не существует магического числа для определения количества сегментов для хеш-индексов. В основном, до тех пор, пока сегменты не будут полностью заполнены, а цепочки рядов останутся ниже 3 или 4, производительность должна оставаться приемлемой. Это все равно, что спросить: «На что мне установить файл журнала?» - это будет зависеть от процесса, базы данных, типа использования.
OPTION(OPTIMIZE FOR UNKNOWN)
(см. Советы по таблице )?