#spring-boot #hibernate #spring-data-jpa
Вопрос:
Я работаю над подготовкой некоторых тестов для структуры базы данных, в которых я сравниваю использование UUID для первичного ключа с последовательным идентификатором. Основываясь на разных статьях, я ожидал, что UUID будет медленнее для вставки и выбора. В большинстве других статей, посвященных этой теме, были простые объекты, но у меня более сложная структура со множеством отношений «один ко многим», поэтому я решил попытать счастья со своими собственными критериями.
У меня была такая структура:
class A {
UUID/Long id;
String name;
UUID uuid; // only when PK is Long
List<B> b; // one to many, 5 items in the list
List<C> c; // one to many, 5 items in the list
}
class B {
UUID/Long id;
String name;
List<D> d; // one to many, 5 items
}
// C and D just have an ID and a name;
Как примечание, у меня есть разные таблицы и разные сущности для UUID и Long PK. Кроме того, в течение длительного времени у меня есть дополнительный столбец UUID для класса A, который заполняется случайным UUID. Кроме того, добавлен индекс для столбца UUID, так как я также буду измерять поиск по этому столбцу.
Я создал приложение в Spring Boot с данными Spring для реализации JPA и MS SQL для базы данных.
Я начал заполнять базу данных в обоих случаях (с UUID PK и длинным PK) 2000 элементами и не увидел никаких существенных различий во времени между двумя тестами.
Затем я провел поиск по UUID. Для первого сценария UUID также является PK. Для второго сценария PK является длинным, а UUID-отдельным столбцом с индексом. Это было намного быстрее.
Далее, только там, где ПК длинный, я провел поиск по ПК, и вот тут меня ждал большой сюрприз. Поиск был почти таким же медленным, как и для UUID PK.
Вот некоторые результаты (тайминги указаны в мс):
Benchmark UUID PK Long PK
2000 Product Insertion 368910 354643
800 items search by UUID, 1 iteration 2582 908
800 items search by UUID, 3 iterations 5853 1981
800 items search by ID, 1 iteration - 1794
800 items search by ID, 3 iterations - 4421
500 Products insertion 38940 39852
200 items search by UUID, 1 iteration 492 167
200 items search by UUID, 5 iterations 1840 763
200 items search by UUID, 10 iterations 3450 1472
200 items search by ID, 1 iteration - 448
200 items search by ID, 5 iterations - 2254
200 items search by ID, 10 iterations - 4588
Я ожидал, что при использовании длинного ПК все будет быстрее, но это не всегда так. Я основывал свои первоначальные предположения в основном на этих двух статьях:
- https://www.mssqltips.com/sqlservertip/5105/sql-server-performance-comparison-int-versus-guid/
- https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439
Я могу согласиться с тем, что даже с UUID PK, если мы исключим фрагментацию БД, время будет аналогичным. Что меня озадачивает, так это то, почему поиск по столбцу UUID выполняется быстрее, чем поиск по PK, когда PK длинный.
Даже когда show_sql был включен, я не видел никаких различий (без выбора *, который, как я знаю, может вызвать замедление). Я также попытался устранить другие факторы, но результаты были последовательными.
Я делаю что-то не так? Я что-то неправильно понимаю? Разве на самом деле не имеет значения, что PK-это UUID, даже с более сложной структурой и множеством элементов?
Комментарии:
1. Я предполагаю, что вы можете увидеть снижение производительности при выполнении больших соединений, но доминирующим фактором при выполнении поиска по одному значению обычно является все остальное (сеть, планировщик и т. Д.), Так что, Вероятно, это не приведет к проблемам с производительностью. Другой возможной проблемой может быть размер индексов и т.д. что затем влияет на кэш страниц и ЦП.
2. @ChristianBeikov Я думал о том же, но условия были те же, особенно с тех пор, как я провел тесты на своей локальной машине, так что сеть не была проблемой. Я также запустил его несколько раз, несколько итераций, и все равно получил те же результаты. Как я уже сказал, я мог бы согласиться с тем, что PK UUID и PK Long одинаковы, но меня беспокоит то, что поиск по UUID с PK Long быстрее, чем поиск по длинному идентификатору. Это для тех же самых записей и того же количества/элементов поиска.
3. Вы уверены, что используете один и тот же индекс?
4. Честно говоря, я не проверял тип индекса. Я предположил, что у ПК будет самый быстрый. Я также расследую это, когда у меня будет время. Спасибо
5. Я не знаю, как SQL Server работает внутренне, но если вы используете процессор, который может эффективно обрабатывать 128-битные значения, и если SQL Server оптимизирован для этого, единственное различие, которое вы можете увидеть, заключается в том, что большие соединения немного медленнее из-за большего объема строк в памяти, но я сомневаюсь, что вы действительно заметите разницу в реальном случае использования. Есть и другие преимущества в производительности, хотя, например, создание B-дерева для последовательности может быть намного дешевле, чем для UUID, поэтому вы, вероятно, увидите меньше разбиений страниц с последовательностью.
Ответ №1:
Так уж получилось, что кто-то написал в блоге о своем анализе bigint против производительность uuid в PostgreSQL в последнее время, которая также может применяться к SQL Server: https://www.cybertec-postgresql.com/en/uuid-serial-or-identity-columns-for-postgresql-auto-generated-primary-keys/
Комментарии:
1. Несмотря на то, что статья хорошая, она не дает мне никакой новой информации. Я знал все, что там было написано. Чего я до сих пор по-настоящему не понимаю (но у меня есть одно предположение), так это почему поиск по ДЛИННОМУ идентификатору был медленнее по сравнению с поиском UUID, хотя длинный идентификатор был PK, в то время как UUID был второстепенным столбцом. Я предполагаю, что это связано с типом индекса между ними.
2. Я думаю, что на SQL Server индекс PK может быть представлен в виде таблицы, организованной по индексу, которая может иметь худшую производительность, чем вторичный индекс, но я действительно недостаточно знаю о SQL Server, чтобы дать вам хороший ответ здесь.