Сохрани себе нервы, когда работаешь с базой данных.
Всегда оборачивай UPDATE или DELETE в транзакцию с откатом — так ты защитишься от случайных косяков.
Лично я первым делом пишу:
Теперь, если что-то пойдёт не так, изменения сразу откатятся при rollback.
Можно спокойно шлифовать запрос, не боясь напортачить.
Когда всё готово и уверен в результате = либо выделяешь нужный SQL и запускаешь напрямую,
либо просто меняешь rollback transaction на commit transaction.
👉 @KodBlog
Всегда оборачивай UPDATE или DELETE в транзакцию с откатом — так ты защитишься от случайных косяков.
Лично я первым делом пишу:
begin transaction
rollback transaction
Теперь, если что-то пойдёт не так, изменения сразу откатятся при rollback.
Можно спокойно шлифовать запрос, не боясь напортачить.
Когда всё готово и уверен в результате = либо выделяешь нужный SQL и запускаешь напрямую,
либо просто меняешь rollback transaction на commit transaction.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
Code Coverage теперь доступен в Visual Studio Community и Professional
Раньше эта функция была только в Enterprise-версии, но теперь любой разработчик может проверить, насколько хорошо его код покрыт тестами - прямо из IDE.
Больше не нужно ставить сторонние плагины или собирать отчёты вручную. Просто запускаешь тесты и Visual Studio показывает, какие участки кода реально выполнялись, а какие остались нетронутыми.
Отличный ход Microsoft👍
👉 @KodBlog
Раньше эта функция была только в Enterprise-версии, но теперь любой разработчик может проверить, насколько хорошо его код покрыт тестами - прямо из IDE.
Больше не нужно ставить сторонние плагины или собирать отчёты вручную. Просто запускаешь тесты и Visual Studio показывает, какие участки кода реально выполнялись, а какие остались нетронутыми.
Отличный ход Microsoft
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16😁2
В .NET считается хорошей практикой задавать размер List<T> при создании. И у меня есть бенчмарк, который это подтверждает.
Если добавить в список 10 миллионов элементов, то версия с заранее заданной емкостью работает примерно на 60% быстрее, чем список, созданный через конструктор по умолчанию.
Проблема на поверхности простая:
- List<T> внутри использует обычный массив
- по умолчанию Capacity = 0
То есть новый экземпляр List<T> всегда стартует с нуля.
Что происходит, когда список заполняется? Создается новый массив!
Когда элементы добавляются, а внутренний массив уже заполнен:
a) создается новый массив (всплеск использования памяти)
b) старые данные копируются в новый массив (лишние операции)
Получается довольно неприятный цикл.
Избежать этого можно, если создавать List<T> сразу с емкостью, примерно соответствующей ожидаемому количеству элементов.
Бенчмарк — добавление 10 миллионов элементов в список.
Тестировались три варианта:
- Capacity = 10_000_000 (равен ожидаемому количеству)
- Capacity = 5_000_000 (половина ожидаемого)
- Capacity = 0 (по умолчанию)
Если за базовую точку взять Capacity = 0:
- при Capacity = 50% — прирост скорости 48%
- при Capacity = 100% — прирост скорости 53%
👉 @KodBlog
Если добавить в список 10 миллионов элементов, то версия с заранее заданной емкостью работает примерно на 60% быстрее, чем список, созданный через конструктор по умолчанию.
Проблема на поверхности простая:
- List<T> внутри использует обычный массив
- по умолчанию Capacity = 0
То есть новый экземпляр List<T> всегда стартует с нуля.
Что происходит, когда список заполняется? Создается новый массив!
Когда элементы добавляются, а внутренний массив уже заполнен:
a) создается новый массив (всплеск использования памяти)
b) старые данные копируются в новый массив (лишние операции)
Получается довольно неприятный цикл.
Избежать этого можно, если создавать List<T> сразу с емкостью, примерно соответствующей ожидаемому количеству элементов.
Бенчмарк — добавление 10 миллионов элементов в список.
Тестировались три варианта:
- Capacity = 10_000_000 (равен ожидаемому количеству)
- Capacity = 5_000_000 (половина ожидаемого)
- Capacity = 0 (по умолчанию)
Если за базовую точку взять Capacity = 0:
- при Capacity = 50% — прирост скорости 48%
- при Capacity = 100% — прирост скорости 53%
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥23❤6⚡3🤔3🤯3
Майкрософт выпустил второй и последний релиз-кандидат .NET 10, который поставляется с лицензией go-live и поэтому уже может использоваться в production. Этот выпуск .NET 10 добавляет главным образом улучшения и исправления уже имеющегося функционала и поддерживается в новом выпуске Visual Studio 2026 Insiders, а также в Visual Studio Code с C# Dev Kit.
Окончательный релиз .NET 10 с C# 14 состоится 11 ноября.
https://devblogs.microsoft.com/dotnet/dotnet-10-rc-2/
👉 @KodBlog
Окончательный релиз .NET 10 с C# 14 состоится 11 ноября.
https://devblogs.microsoft.com/dotnet/dotnet-10-rc-2/
Please open Telegram to view this post
VIEW IN TELEGRAM
Microsoft News
Announcing .NET 10 Release Candidate 2
.NET 10 Release Candidate 2 focuses on final quality, reliability, and stabilization across the runtime, SDK, libraries, ASP.NET Core, Blazor, .NET MAUI, and more.
👍8🔥3👏2
Есть вещи в C#, которые настолько базовые для современного .NET, что игнорировать их почти преступление. Это не модные фишки, а практичные инструменты, по которым легко отличить код новичка от кода опытного разработчика.
1. Проверка зависимостей на старте
Одна из типичных проблем .NET-приложений — когда сервис вроде бы создаётся без ошибок, но позже падает из-за недопустимых значений времени жизни или отсутствующих зависимостей. Такое можно ловить заранее.
Как делает новичок:
Ошибка проявится только при первом же запросе.
Как делает опытный:
Эти настройки заставляют контейнер проверить конфигурацию при сборке приложения. ValidateScopes выявляет, например, внедрение scoped-сервиса в singleton, а ValidateOnBuild — пробует создать сервисы ещё до запуска. Ошибки проявятся сразу, а не в проде.
2. Осознанное использование областей действия
Многие просто лепят всё в Transient, не задумываясь, что это вообще значит. А время жизни сервисов — это не синтаксис, это логика памяти приложения.
Типичный пример:
Без понимания, когда объект должен жить и когда исчезать.
Что знает опытный разработчик:
- Transient – новый экземпляр каждый раз,
- Scoped – один экземпляр на запрос/скоуп DI,
- Singleton – один экземпляр на всё время жизни приложения.
Создавая свой скоуп, можно изолировать контексты:
Так удобно, например, для отдельных пользователей, фоновых заданий или временных контекстов.
3. DateTimeOffset вместо DateTime
Новички часто спотыкаются на часовых поясах и летнем времени. Всё вроде работает... пока не перестаёт.
Плохой вариант:
В другом часовом поясе это может поехать.
Хороший вариант:
DateTimeOffset хранит не только момент времени, но и смещение. Это идеально для логов, транзакций и расписаний. Храните в UTC, показывайте пользователю в его часовом поясе.
4. Алиасы для пространств имён и типов
Длинные неймспейсы и вложенные типы быстро превращают код в кашу. Но немногие используют алиасы.
До:
После:
Алиасы — это не просто сокращение, это способ упростить чтение и сделать код гибче. При смене библиотеки или рефакторинге правите одну строчку и всё работает.
👉 @KodBlog
1. Проверка зависимостей на старте
Одна из типичных проблем .NET-приложений — когда сервис вроде бы создаётся без ошибок, но позже падает из-за недопустимых значений времени жизни или отсутствующих зависимостей. Такое можно ловить заранее.
Как делает новичок:
builder.Services.AddScoped<IMyService, MyService>();
// Без проверки
Ошибка проявится только при первом же запросе.
Как делает опытный:
var builder = Program.CreateHostBuilder(args);
builder.Services.AddScoped<IMyService, MyService>();
builder.Host.UseDefaultServiceProvider((context, options) =>
{
options.ValidateOnBuild = true;
options.ValidateScopes = true;
});
Эти настройки заставляют контейнер проверить конфигурацию при сборке приложения. ValidateScopes выявляет, например, внедрение scoped-сервиса в singleton, а ValidateOnBuild — пробует создать сервисы ещё до запуска. Ошибки проявятся сразу, а не в проде.
2. Осознанное использование областей действия
Многие просто лепят всё в Transient, не задумываясь, что это вообще значит. А время жизни сервисов — это не синтаксис, это логика памяти приложения.
Типичный пример:
builder.Services.AddTransient<UserSession>();
Без понимания, когда объект должен жить и когда исчезать.
Что знает опытный разработчик:
- Transient – новый экземпляр каждый раз,
- Scoped – один экземпляр на запрос/скоуп DI,
- Singleton – один экземпляр на всё время жизни приложения.
Создавая свой скоуп, можно изолировать контексты:
using var scope = serviceProvider.CreateScope();
var scopedService = scope.ServiceProvider.GetRequiredService<IScopedThing>();
Так удобно, например, для отдельных пользователей, фоновых заданий или временных контекстов.
3. DateTimeOffset вместо DateTime
Новички часто спотыкаются на часовых поясах и летнем времени. Всё вроде работает... пока не перестаёт.
Плохой вариант:
var orderTime = DateTime.Now; // локальное время
В другом часовом поясе это может поехать.
Хороший вариант:
var orderTime = DateTimeOffset.Now;
DateTimeOffset хранит не только момент времени, но и смещение. Это идеально для логов, транзакций и расписаний. Храните в UTC, показывайте пользователю в его часовом поясе.
4. Алиасы для пространств имён и типов
Длинные неймспейсы и вложенные типы быстро превращают код в кашу. Но немногие используют алиасы.
До:
System.Collections.Generic.Dictionary<System.Tuple<string, int>, List<MyNamespace.Models.ComplexThing>> myMap;
После:
using ComplexMap = System.Collections.Generic.Dictionary<(string, int), List<ComplexThing>>;
Алиасы — это не просто сокращение, это способ упростить чтение и сделать код гибче. При смене библиотеки или рефакторинге правите одну строчку и всё работает.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍6❤5
Новичок в C#: «Когда стоит использовать static-класс?»
NPC-ответ: «Когда тебе не нужен экземпляр».
Формально верно, но бесполезно. Такой ответ помогает только самооценке того, кто его дал.
На практике всё проще и понятнее:
Используй обычный класс, когда хочешь смоделировать систему, чтобы её было легче понять и использовать.
Система это набор связанных данных и операций над ними.
Например, табло очков (scoreboard): у него есть данные (очки, имена, время), и есть поведение (обновить счёт, сбросить, вывести). Ценность в целостности системы, а не в отдельном поле.
Если ты не моделируешь систему, то обычный класс может быть полезен ещё и ради dependency injection, когда нужно, чтобы внешний код управлял зависимостями, временем жизни и контекстом. Это упрощает тестирование и структуру проекта.
Но если ты не моделируешь и не внедряешь зависимости, тогда используй static-класс.
Всё, что ты делаешь это, скорее всего, утилитарная операция, которая не зависит от состояния и может применяться к любым данным.
Честно говоря, можно было бы даже сказать, что static-классы должны быть дефолтом, а instance использовать только тогда, когда действительно есть повод включать ООП.
👉 @KodBlog
NPC-ответ: «Когда тебе не нужен экземпляр».
Формально верно, но бесполезно. Такой ответ помогает только самооценке того, кто его дал.
На практике всё проще и понятнее:
Используй обычный класс, когда хочешь смоделировать систему, чтобы её было легче понять и использовать.
Система это набор связанных данных и операций над ними.
Например, табло очков (scoreboard): у него есть данные (очки, имена, время), и есть поведение (обновить счёт, сбросить, вывести). Ценность в целостности системы, а не в отдельном поле.
Если ты не моделируешь систему, то обычный класс может быть полезен ещё и ради dependency injection, когда нужно, чтобы внешний код управлял зависимостями, временем жизни и контекстом. Это упрощает тестирование и структуру проекта.
Но если ты не моделируешь и не внедряешь зависимости, тогда используй static-класс.
Всё, что ты делаешь это, скорее всего, утилитарная операция, которая не зависит от состояния и может применяться к любым данным.
Честно говоря, можно было бы даже сказать, что static-классы должны быть дефолтом, а instance использовать только тогда, когда действительно есть повод включать ООП.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17👎2😁1
Встраивать бизнес-логику прямо в SQL-запросы?
Это верный способ превратить код в нечто нетестируемое и хрупкое.
Представь, ты делаешь поиск по инвойсам. Нужно фильтровать по:
- номеру инвойса
- имени клиента
- email
- статусу заказа
- названию продукта
И всё это в любых комбинациях.
Самое быстрое, но грязное решение — напихать всю эту логику прямо в SQL-запрос.
И вот теперь все твои бизнес-правила оказались заперты внутри базы.
Тестировать их без реальной базы уже не выйдет.
Альтернатива — Specification Pattern.
Это способ вынести сложную логику формирования запросов в отдельный класс, чтобы можно было её переиспользовать и тестировать.
Как это работает:
Создаёшь класс спецификации, который описывает критерии поиска.
Он принимает фильтры и строит выражение (например, LINQ).
Потом передаёшь эту спецификацию в репозиторий или обработчик запросов.
Этот подход отлично подходит для фильтрации и сложных запросов.
Результат:
- тесты запускаются быстрее
- бизнес-логика понятнее
- код запросов проще поддерживать
Specification Pattern это про то, чтобы держать логику в месте, где её можно понять, протестировать и не проклинать через полгода.🔫
👉 @KodBlog
Это верный способ превратить код в нечто нетестируемое и хрупкое.
Представь, ты делаешь поиск по инвойсам. Нужно фильтровать по:
- номеру инвойса
- имени клиента
- статусу заказа
- названию продукта
И всё это в любых комбинациях.
Самое быстрое, но грязное решение — напихать всю эту логику прямо в SQL-запрос.
И вот теперь все твои бизнес-правила оказались заперты внутри базы.
Тестировать их без реальной базы уже не выйдет.
Альтернатива — Specification Pattern.
Это способ вынести сложную логику формирования запросов в отдельный класс, чтобы можно было её переиспользовать и тестировать.
Как это работает:
Создаёшь класс спецификации, который описывает критерии поиска.
Он принимает фильтры и строит выражение (например, LINQ).
Потом передаёшь эту спецификацию в репозиторий или обработчик запросов.
Этот подход отлично подходит для фильтрации и сложных запросов.
Результат:
- тесты запускаются быстрее
- бизнес-логика понятнее
- код запросов проще поддерживать
Specification Pattern это про то, чтобы держать логику в месте, где её можно понять, протестировать и не проклинать через полгода.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥3👍2
На Хабре вышла статья о том, как с помощью EF Core и PostgreSQL избежать deadlock и oversell при работе со стоками. Автор разбирает подход с сортировкой обновлений по ключам, использованием ExecuteUpdateAsync, повторными попытками (retry), триггерами, очередями и батчами.
В статье есть бенчмарки, примеры кода и ссылка на репозиторий на GitHub.
Читать подробнее: habr.com/ru/articles/955714/
👉 @KodBlog
В статье есть бенчмарки, примеры кода и ссылка на репозиторий на GitHub.
Читать подробнее: habr.com/ru/articles/955714/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2
В превью C# 14 появились partial-конструкторы и partial-события.
Каждый из них должен состоять ровно из одного объявления-определения и одного объявления-реализации.
Реализация partial-события обязана содержать add и remove аксессоры.
👉 @KodBlog
Каждый из них должен состоять ровно из одного объявления-определения и одного объявления-реализации.
Реализация partial-события обязана содержать add и remove аксессоры.
Please open Telegram to view this post
VIEW IN TELEGRAM
👎8👍4🤔2
На GitHub появился классный репозиторий с чётко структурированным материалом по system design. В нём собраны:
- основы проектирования крупных систем,
- типичные вопросы и решения для собеседований,
- карточки Anki для запоминания ключевых концепций.
Сохрани, чтобы не потерять: https://github.com/donnemartin/system-design-primer
👉 @KodBlog
- основы проектирования крупных систем,
- типичные вопросы и решения для собеседований,
- карточки Anki для запоминания ключевых концепций.
Сохрани, чтобы не потерять: https://github.com/donnemartin/system-design-primer
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
Ты правильно называешь свои DTO?
Какую схему именования выбрать
Когда ты делаешь Web API, твои эндпоинты принимают и отдают данные.
Частая практика — добавлять к таким моделям суффикс Dto
Но вот в чём проблема:
DTO часто смешивают входные и выходные данные в одном классе.
Со временем такие классы разрастаются и становятся непонятными.
Мой вариант: использовать суффиксы Request и Response вместо Dto:
• CreateUserRequest —> для входных данных
• UserResponse —> для выходных
Почему так лучше:
Чёткое назначение —> сразу видно, модель для входа или для выхода.
Масштабируемость —> изменения в Response не ломают Request.
Поддерживаемость —> не надо гадать, что вообще делает UserDto.
Совет: выбери один подход и используй его последовательно во всём проекте.
А ты как называешь свои модели Request/Response или Dto? Делись опытом
👉 @KodBlog
Какую схему именования выбрать
Когда ты делаешь Web API, твои эндпоинты принимают и отдают данные.
Частая практика — добавлять к таким моделям суффикс Dto
Но вот в чём проблема:
DTO часто смешивают входные и выходные данные в одном классе.
Со временем такие классы разрастаются и становятся непонятными.
Мой вариант: использовать суффиксы Request и Response вместо Dto:
• CreateUserRequest —> для входных данных
• UserResponse —> для выходных
Почему так лучше:
Чёткое назначение —> сразу видно, модель для входа или для выхода.
Масштабируемость —> изменения в Response не ломают Request.
Поддерживаемость —> не надо гадать, что вообще делает UserDto.
Совет: выбери один подход и используй его последовательно во всём проекте.
А ты как называешь свои модели Request/Response или Dto? Делись опытом
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍8🤣3🔥2
Деревья выражений в C# помогают создавать быстрые и эффективные методы преобразования данных, ускоряя работу с объектами и запросами в Entity Framework Core. В статье раскрываются механизмы мэппинга и построения сложных фильтров через IQueryable.
Читать подробнее: https://habr.com/ru/articles/932110/
👉 @KodBlog
Читать подробнее: https://habr.com/ru/articles/932110/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3
Экономим память как профи: 5 продвинутых техник
Если вы работаете с .NET, то знаете, под капотом куча мощных инструментов, про которые редко говорят. Вот 5 API, которые реально экономят память и ускоряют код.
1. CollectionsMarshal.AsSpan() — прямой доступ к списку
Обычно List<T> это удобная, но безопасная обёртка над массивом.
Если нужен Span без копирования:
Работает напрямую с внутренним массивом списка, без ToArray().
Важно: при изменении размера списка Span станет недействительным.
Когда использовать: большие буферы, короткие циклы.
Выигрыш: до 2 раз меньше памяти.
2. CollectionsMarshal.GetValueRefOrNullRef() — доступ к словарю без двойного поиска
Обычный способ вызывает поиск ключа дважды:
Лучше так:
Получаем ссылку прямо на значение без повторного поиска.
Когда использовать: большие словари, горячие циклы.
Выигрыш: примерно в 2 раза быстрее.
3. GC.AllocateUninitializedArray<T>() — массив без обнуления
.NET по умолчанию обнуляет массив:
Если вы всё равно перезаписываете элементы - то это лишняя работа.
Быстрее:
Когда использовать: если массив заполняется сразу.
Выигрыш: ~15% быстрее на больших массивах.
4. ArrayPool<T>.Shared и IMemoryOwner — аренда массивов
Постоянные аллокации убивают GC:
Используем пул:
Когда использовать: сетевые серверы, конвейеры, потоковые операции.
Выигрыш: до 1000 раз меньше аллокаций.
5. ObjectPool<T> — переиспользование дорогих объектов
Создание тяжёлых объектов вроде StringBuilder дорого:
Пулим:
Когда использовать: логирование, сериализация, временные буферы.
Выигрыш: до 4 раз быстрее, в 50 раз меньше памяти.
Если вы когда-нибудь заглядывали в свой профилировщик и задавались вопросом, почему так много времени тратится на сборку мусора или копирование памяти, эти приёмы помогут вам это исправить. Они требуют аккуратности, но дают настоящую производительность.
👉 @KodBlog
Если вы работаете с .NET, то знаете, под капотом куча мощных инструментов, про которые редко говорят. Вот 5 API, которые реально экономят память и ускоряют код.
1. CollectionsMarshal.AsSpan() — прямой доступ к списку
Обычно List<T> это удобная, но безопасная обёртка над массивом.
Если нужен Span без копирования:
using System.Runtime.InteropServices;
var numbers = new List<int> { 1, 2, 3, 4, 5 };
Span<int> span = CollectionsMarshal.AsSpan(numbers);
Работает напрямую с внутренним массивом списка, без ToArray().
Важно: при изменении размера списка Span станет недействительным.
Когда использовать: большие буферы, короткие циклы.
Выигрыш: до 2 раз меньше памяти.
2. CollectionsMarshal.GetValueRefOrNullRef() — доступ к словарю без двойного поиска
Обычный способ вызывает поиск ключа дважды:
if (dict.TryGetValue("foo", out var value)) {
value++;
dict["foo"] = value;
}Лучше так:
using System.Runtime.InteropServices;
ref int valueRef = ref CollectionsMarshal.GetValueRefOrNullRef(dict, "foo");
if (!Unsafe.IsNullRef(ref valueRef))
valueRef++;
Получаем ссылку прямо на значение без повторного поиска.
Когда использовать: большие словари, горячие циклы.
Выигрыш: примерно в 2 раза быстрее.
3. GC.AllocateUninitializedArray<T>() — массив без обнуления
.NET по умолчанию обнуляет массив:
int[] arr = new int[1000];
Если вы всё равно перезаписываете элементы - то это лишняя работа.
Быстрее:
int[] arr = GC.AllocateUninitializedArray<int>(1000);
for (int i = 0; i < arr.Length; i++) arr[i] = i;
Когда использовать: если массив заполняется сразу.
Выигрыш: ~15% быстрее на больших массивах.
4. ArrayPool<T>.Shared и IMemoryOwner — аренда массивов
Постоянные аллокации убивают GC:
for (int i = 0; i < 1000; i++) {
var buffer = new byte[1024];
DoSomething(buffer);
}Используем пул:
using System.Buffers;
for (int i = 0; i < 1000; i++) {
using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(1024);
DoSomething(owner.Memory.Span);
}
Когда использовать: сетевые серверы, конвейеры, потоковые операции.
Выигрыш: до 1000 раз меньше аллокаций.
5. ObjectPool<T> — переиспользование дорогих объектов
Создание тяжёлых объектов вроде StringBuilder дорого:
for (int i = 0; i < 100; i++) {
var sb = new StringBuilder(1024);
sb.Append("Hello ").Append(i);
Console.WriteLine(sb.ToString());
}Пулим:
using Microsoft.Extensions.ObjectPool;
var provider = new DefaultObjectPoolProvider();
var pool = provider.CreateStringBuilderPool();
for (int i = 0; i < 100; i++) {
var sb = pool.Get();
sb.Clear();
sb.Append("Hello ").Append(i);
Console.WriteLine(sb.ToString());
pool.Return(sb);
}
Когда использовать: логирование, сериализация, временные буферы.
Выигрыш: до 4 раз быстрее, в 50 раз меньше памяти.
Если вы когда-нибудь заглядывали в свой профилировщик и задавались вопросом, почему так много времени тратится на сборку мусора или копирование памяти, эти приёмы помогут вам это исправить. Они требуют аккуратности, но дают настоящую производительность.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9
Rider 2025.3 EAP 6 уже доступен!
В этом билде появилась поддержка ASP. NET и обнаружения проблем с базой данных прямо в окне Monitoring🔥
Теперь, когда ты запускаешь или отлаживаешь приложение, мониторинг автоматически определяет:
Медленные или чрезмерно частые запросы к БД
Слишком большие результаты выборок
Медленные действия MVC или обработчики Razor-страниц
…и многое другое
Подробнее — здесь
👉 @KodBlog
В этом билде появилась поддержка ASP. NET и обнаружения проблем с базой данных прямо в окне Monitoring
Теперь, когда ты запускаешь или отлаживаешь приложение, мониторинг автоматически определяет:
Медленные или чрезмерно частые запросы к БД
Слишком большие результаты выборок
Медленные действия MVC или обработчики Razor-страниц
…и многое другое
Подробнее — здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14
This media is not supported in your browser
VIEW IN TELEGRAM
Задумывался, почему приложение ощущается «тормозным», хотя с пропускной способностью вроде всё ок? Дело в том, что latency и throughput описывают два совершенно разных аспекта производительности.
Latency — это задержка на один пакет. То, что ощущает пользователь, когда нажимает кнопку. Это отзывчивость системы. Это время, за которое один запрос проходит путь от сервера до конечного устройства. В это входит время обработки на сервере, ожидание в очереди, распространение по сети, задержка при передаче и последний участок соединения до устройства пользователя.
Throughput — это объём данных в секунду. Не скорость отдельного пакета, а то, сколько пакетов проходит через «трубу» за определённый промежуток времени. Throughput — это ёмкость системы. Высокий throughput означает, что система справляется с нагрузкой, не захлёбываясь.
👉 @KodBlog
Latency — это задержка на один пакет. То, что ощущает пользователь, когда нажимает кнопку. Это отзывчивость системы. Это время, за которое один запрос проходит путь от сервера до конечного устройства. В это входит время обработки на сервере, ожидание в очереди, распространение по сети, задержка при передаче и последний участок соединения до устройства пользователя.
Throughput — это объём данных в секунду. Не скорость отдельного пакета, а то, сколько пакетов проходит через «трубу» за определённый промежуток времени. Throughput — это ёмкость системы. Высокий throughput означает, что система справляется с нагрузкой, не захлёбываясь.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤3👏2
C# и LINQ = функциональный коктейль для кодинга
Если объяснить максимально просто — функциональный стиль позволяет писать код так, как ты о нём говоришь.
«Отфильтровать пользователей старше 30»
«Сгруппировать пользователей по школе»
«Показать все имена пользователей»
В отличие от процедурного подхода, где нужно думать и о том, что делать, и как именно это сделать — управлять переменными, добавлять и удалять элементы из списков, сортировать результаты и так далее.
В LINQ больше двух десятков операторов, но чтобы начать, достаточно пары базовых:
Select — выбрать нужные данные
Where — отфильтровать записи
Any — проверить, существует ли хотя бы один элемент
GroupBy — сгруппировать совпадающие элементы
ToList — собрать результат в List<T>
ToDictionary — собрать результат в Dictionary<K,V>
👉 @KodBlog
Если объяснить максимально просто — функциональный стиль позволяет писать код так, как ты о нём говоришь.
«Отфильтровать пользователей старше 30»
«Сгруппировать пользователей по школе»
«Показать все имена пользователей»
В отличие от процедурного подхода, где нужно думать и о том, что делать, и как именно это сделать — управлять переменными, добавлять и удалять элементы из списков, сортировать результаты и так далее.
В LINQ больше двух десятков операторов, но чтобы начать, достаточно пары базовых:
Select — выбрать нужные данные
Where — отфильтровать записи
Any — проверить, существует ли хотя бы один элемент
GroupBy — сгруппировать совпадающие элементы
ToList — собрать результат в List<T>
ToDictionary — собрать результат в Dictionary<K,V>
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22❤2
Одно небольшое изменение = запрос в 400 раз быстрее
Вот что было сделано, чтобы добиться такого прироста.
Реализовывалась пагинация с курсором через EF и Postgres.
Но нужно было сделать запрос быстрее.
Как ускорить SQL-запрос?
Добавить индекс, и всё должно полететь.
Так ведь?
Не совсем…
Был создан составной индекс по нужным колонкам, чтобы ускорить выборку.
НО ЗАПРОС СТАЛ МЕДЛЕННЕЕ!!!
Пришлось разбираться, почему индекс не используется.
Оказалось, что дело в сравнении кортежей — это и решило проблему.
Но непонятно было, как перенести это в запрос EF Core.
К счастью, провайдер Postgres поддерживает это через кастомную функцию.
👉 @KodBlog
Вот что было сделано, чтобы добиться такого прироста.
Реализовывалась пагинация с курсором через EF и Postgres.
Но нужно было сделать запрос быстрее.
Как ускорить SQL-запрос?
Добавить индекс, и всё должно полететь.
Так ведь?
Не совсем…
Был создан составной индекс по нужным колонкам, чтобы ускорить выборку.
НО ЗАПРОС СТАЛ МЕДЛЕННЕЕ!!!
Пришлось разбираться, почему индекс не используется.
Оказалось, что дело в сравнении кортежей — это и решило проблему.
Но непонятно было, как перенести это в запрос EF Core.
К счастью, провайдер Postgres поддерживает это через кастомную функцию.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3
Настройка batch size в Entity Framework
По умолчанию для провайдера SQL Server batch size равен 42.
Это значит, что при вставке 100 строк произойдёт 5 отдельных запросов к базе.
Я недавно гонял простой бенчмарк в .NET, и вот что получилось:
даже если уменьшить количество раунд-трипов, batch size 1000 оказался самым медленным, а вот 200 показал себя лучше всего — некий "sweet spot".
Вывод простой: тестируйте на своих сценариях.
Оптимальный размер batch может отличаться в зависимости от типа нагрузки и объёмов данных.
👉 @KodBlog
По умолчанию для провайдера SQL Server batch size равен 42.
Это значит, что при вставке 100 строк произойдёт 5 отдельных запросов к базе.
Я недавно гонял простой бенчмарк в .NET, и вот что получилось:
даже если уменьшить количество раунд-трипов, batch size 1000 оказался самым медленным, а вот 200 показал себя лучше всего — некий "sweet spot".
Вывод простой: тестируйте на своих сценариях.
Оптимальный размер batch может отличаться в зависимости от типа нагрузки и объёмов данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1