.NET funguje dobře se všemi třemi. SQL Server má nejhlubší nástroje a provider, který píše sám Microsoft, PostgreSQL má Npgsql, který je výborný a stejně rychlý jako cokoli v ekosystému, a MySQL má MySqlConnector pod komunitním providerem Pomelo pro Entity Framework Core. Volba se týká spíš databáze než ovladače: SQL Server Express je zdarma, ale omezený na 10 GB na databázi a zhruba 1,4 GB paměti pro buffer; PostgreSQL nemá žádná omezení edic a nabízí nejbohatší sadu funkcí; MySQL je všude a je nejlehčí na provoz. Jakmile si vybereš, věci, které dělají potíže, jsou u všech stejné - connection string, velikost poolu, chování dat a řetězců a udržování migrací specifických pro daný provider. Tento článek je probírá všechny vedle sebe.
Providery a ovladače#
Každý databázový stack v .NET má dvě vrstvy. Dole je ovladač ADO.NET, který mluví síťovým protokolem databáze a implementuje DbConnection a DbCommand. Nad ním volitelně stojí provider Entity Framework Core, který překládá LINQ do SQL dialektu dané databáze. Dapper a ručně psané SQL používají ovladač přímo.
| Databáze | Ovladač ADO.NET | Provider EF Core | Udržuje |
|---|---|---|---|
| PostgreSQL | Npgsql | Npgsql.EntityFrameworkCore.PostgreSQL | Projekt Npgsql |
| MySQL | MySqlConnector | Pomelo.EntityFrameworkCore.MySql | Komunita (Pomelo, MySqlConnector) |
| MySQL (alternativa) | MySql.Data | MySql.EntityFrameworkCore | Oracle |
| SQL Server | Microsoft.Data.SqlClient | Microsoft.EntityFrameworkCore.SqlServer | Microsoft |
Pár poznámek k té tabulce:
- `System.Data.SqlClient` je starý ovladač SQL Serveru a je zastaralý. Nový kód i každá současná verze EF Core používají
Microsoft.Data.SqlClient. Zkopírovaný příklad se starým jmenným prostorem se pořád zkompiluje a dostaneš ovladač se staršími výchozími hodnotami a bez nových oprav. - Pro MySQL dej přednost MySqlConnector. Má licenci MIT, je skutečně asynchronní (
MySql.Dataod Oracle své asynchronní metody historicky implementoval synchronně) a používá ho Pomelo. Balíčky Oracle jsou pod GPL s výjimkou pro FOSS, což u některých komerčních projektů hraje roli. - Vydání Pomelo následují major verze EF Core, někdy s měsíčním zpožděním. Než povýšíš EF Core na novou major verzi, ověř, že odpovídající vydání Pomelo existuje. Npgsql svůj provider pro EF Core obvykle vydává blízko vydání Microsoftu.
Zapojení každého z nich s EF Core#
Registrace vypadá u všech tří téměř stejně, což je smysl EF Core:
// PostgreSQLbuilder.Services.AddDbContext<AppDbContext>(o => o.UseNpgsql(builder.Configuration.GetConnectionString("Default")));// MySQL via Pomelovar mysql = builder.Configuration.GetConnectionString("Default");builder.Services.AddDbContext<AppDbContext>(o => o.UseMySql(mysql, ServerVersion.AutoDetect(mysql)));// SQL Serverbuilder.Services.AddDbContext<AppDbContext>(o => o.UseSqlServer(builder.Configuration.GetConnectionString("Default")));Pomelo potřebuje znát verzi serveru, protože MySQL a MariaDB se liší v SQL, které přijímají. ServerVersion.AutoDetect se při startu připojí a zeptá se, což shodí start aplikace, pokud je databáze v tu chvíli nedostupná; new MySqlServerVersion(new Version(8, 4, 0)) se tomu zbytečnému volání vyhne a v produkci je lepší volba.
U Npgsql doporučují verze 7 a novější vytvořit NpgsqlDataSource jednou a předat ho EF Core nebo ho používat přímo; tam se nastavují mapování typů, enumy a logování:
var dataSource = new NpgsqlDataSourceBuilder( builder.Configuration.GetConnectionString("Default")).Build();builder.Services.AddDbContext<AppDbContext>(o => o.UseNpgsql(dataSource));GetConnectionString("Default") čte z konfigurace ConnectionStrings:Default, což v produkci nastavíš proměnnou prostředí ConnectionStrings__Default. Connection string je tajemství; do appsettings.json v repozitáři nepatří. Konfigurace a tajemství v ASP.NET Core popisuje vrstvení konfigurace.
Connection stringy vedle sebe#
PostgreSQL (Npgsql)Host=db.example.net;Port=5432;Database=app;Username=app;Password=...;SSL Mode=PreferMySQL (MySqlConnector)Server=db.example.net;Port=3306;Database=app;User ID=app;Password=...;SslMode=PreferredSQL Server (Microsoft.Data.SqlClient)Server=tcp:db.example.net,1433;Database=app;User ID=app;Password=...;Encrypt=True;TrustServerCertificate=TrueRozdíly, na kterých lidé klopýtají:
- SQL Server píše port za čárku, ne za dvojtečku, a nemá samostatné klíčové slovo
Port.db.example.net:1433se přečte jako název hostitele a selže. Stejná čárka se objevuje v poli s názvem serveru v SQL Server Management Studiu. - SQL Server šifruje ve výchozím stavu. Od
Microsoft.Data.SqlClient4.0 (a tedy od EF Core 7) jeEncryptve výchozím stavuTruea ovladač ověřuje certifikát serveru. Server s self-signed certifikátem - jaký si SQL Server vygeneruje sám, když žádný nenastavíš - selže s hláškou „The certificate chain was issued by an authority that is not trusted“, dokud nepřidášTrustServerCertificate=Truenebo nenainstaluješ důvěryhodný certifikát. Connection stringy SQL Serveru projde variantu pro každý ovladač. - MySQL 8.4 se ověřuje přes `caching_sha2_password`. Přes nešifrované spojení potřebuje první přihlášení veřejný klíč RSA serveru a MySqlConnector odmítne s hláškou „Retrieval of the RSA public key is not enabled for insecure connections“, pokud nepoužiješ TLS (
SslMode=Required) nebo nepřidášAllowPublicKeyRetrieval=True. Dej přednost TLS. - Výchozí hodnota Npgsql je `SSL Mode=Prefer`, která použije TLS, když ho server nabízí, ale certifikát neověřuje. Použij
Require, aby se odmítl nešifrovaný provoz, aVerifyFulls důvěryhodnou CA, když potřebuješ certifikát kontrolovat.
Hesla obsahující ; nebo = se v connection stringech ADO.NET musí dát do uvozovek - Password="a;b=c" - nebo se musí sestavit třídou ConnectionStringBuilder daného ovladače, která escapuje za tebe.
Connection pooling a timeouty#
Všechny tři ovladače poolují spojení ve výchozím stavu, jeden pool na každý odlišný connection string v procesu. Otevření spojení si jedno z poolu vezme, uvolnění ho vrátí. Proto je standardní vzor - DbContext na požadavek, uvolněný na jeho konci - levný.
| Nastavení | Npgsql | MySqlConnector | SqlClient |
|---|---|---|---|
| Max. velikost poolu | Maximum Pool Size=100 | MaximumPoolSize=100 | Max Pool Size=100 |
| Min. velikost poolu | Minimum Pool Size=0 | MinimumPoolSize=0 | Min Pool Size=0 |
| Timeout připojení | Timeout=15 | ConnectionTimeout=15 | Connect Timeout=15 |
| Timeout příkazu | Command Timeout=30 | DefaultCommandTimeout=30 | 30 s (na příkaz) |
| Odstraňování nečinných spojení | Connection Idle Lifetime=300 | ConnectionIdleTimeout=180 | Řídí ovladač |
Hodnoty jsou v sekundách. Sto spojení na proces je mnohem víc, než kolik malý databázový server dokáže dobře využít. Zvlášť PostgreSQL utrácí za každé spojení skutečnou paměť a databáze na plánu s 1 nebo 2 GB má max_connections hluboko pod tím, co by mohly otevřít tři instance aplikace s výchozími pooly. Dimenzuj pool podle databáze, ne naopak: dvacet až třicet spojení je pro většinu aplikací na malém serveru víc než dost a aplikace, která potřebuje víc, obvykle drží spojení příliš dlouho. Connection pooly a limity vysvětluje, proč bývá menší pool rychlejší.
Když se pool vyčerpá, požadavky čekají na timeout připojení a pak selžou s chybou timeoutu poolu. Ta chyba téměř nikdy neznamená, že je pool příliš malý. Znamená, že spojení unikají (nejsou uvolněná) nebo se drží přes pomalou práci - například HTTP volání uprostřed transakce.
EF Core má vlastní, samostatný pool: AddDbContextPool<AppDbContext>() opakovaně používá instance DbContext (ve výchozím stavu až 1024), aby ušetřil alokace. Nemění, kolik databázových spojení existuje, a vyžaduje, aby tvůj kontext nedržel žádný stav vázaný na požadavek.
Opakování a přechodné chyby#
Sítě ztrácejí pakety a databáze se restartují. EF Core umí neúspěšné operace automaticky opakovat:
o.UseSqlServer(conn, sql => sql.EnableRetryOnFailure( maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorNumbersToAdd: null));o.UseNpgsql(conn, pg => pg.EnableRetryOnFailure());o.UseMySql(conn, version, my => my.EnableRetryOnFailure());Se zapnutými opakováními vyhodí transakce, kterou si otevřeš sám přes BeginTransactionAsync, výjimku, protože EF Core nedokáže přehrát půlku transakce. Celou jednotku práce obal místo toho do execution strategy:
var strategy = db.Database.CreateExecutionStrategy();await strategy.ExecuteAsync(async () =>{ await using var tx = await db.Database.BeginTransactionAsync(); // ... several SaveChangesAsync calls await tx.CommitAsync();});Opakování skryjí krátké výpadky. Databázi, která opravdu nejede, ale po dobu opakování nechají vypadat jako velmi pomalou aplikaci, takže drž počty skromné a každé opakování loguj.
Rozdíly, které bolí při přechodu#
EF Core skrývá SQL dialekt. Neskrývá chování databáze a na tyto rozdíly lidé narazí, když přesouvají aplikaci z jednoho enginu na druhý nebo píšou testy proti SQLite a produkci provozují na něčem jiném:
- Porovnávání řetězců a velikost písmen. Výchozí collation SQL Serveru (
SQL_Latin1_General_CP1_CI_AS) a výchozí collation MySQL 8 (utf8mb4_0900_ai_ci) porovnávají bez ohledu na velikost písmen, takžeWHERE Email = 'Bob@x.com'najdebob@x.com. PostgreSQL porovnává s ohledem na velikost písmen. Vyhledání uživatele při přihlášení, které fungovalo na SQL Serveru, na PostgreSQL potichu selže. Normalizuj e-maily při zápisu, nebo na PostgreSQL použij collation bez ohledu na velikost písmen či typcitext. - Data a časová pásma. Npgsql 6 a novější mapují
DateTimenatimestamp with time zonea odmítnou zapsatDateTime, jehožKindneníUtc, s hláškou „Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone'“. Ukládej všude UTC, nebo použijDateTimeOffset.datetime2v SQL Serveru adatetimev MySQL neukládají pásmo vůbec, takže stejný kód zapíše místní časy bez stížností a chyba se projeví až později. - Unicode. Na SQL Serveru mapuje EF Core
stringnanvarchar, což je Unicode. Ručně psané tabulky se sloupcivarcharmohou ztratit znaky mimo znakovou stránku collation. Na MySQL používejutf8mb4- starší aliasutf8je tříbajtový a emoji uložit neumí. Collation a Unicode v SQL Serveru a MySQL utf8mb4 a collation jdou víc do hloubky. - Výchozí délky řetězců. Neohraničená vlastnost typu
stringse stanenvarchar(max)na SQL Serveru,longtextna MySQL atextna PostgreSQL. Na SQL Serveru nemohou být sloupcenvarchar(max)klíči indexu; vlastnostem, podle kterých budeš filtrovat, dej[MaxLength]. - Hodnoty identity. Všechny tři generují klíče přes
IDENTITY,AUTO_INCREMENTnebo sloupce identity opřené o sekvence. Mezery jsou po rollbacích a restartech normální u všech; nikdy nepoužívej klíč jako počet. - Migrace jsou specifické pro provider. Migrace vygenerovaná proti SQL Serveru obsahuje typy sloupců a anotace SQL Serveru. Změna enginu znamená vygenerovat migrace pro nový provider od nuly, ne znovu použít původní složku.
Výběr databáze pro aplikaci v .NET#
Podle funkcí zvládne typickou webovou aplikaci kterákoli ze tří. Volba obvykle záleží na limitech, nástrojích a na tom, co už znáš.
SQL Server Express se hodí pro týmy, které žijí v SQL Server Management Studiu, pro aplikace využívající funkce specifické pro SQL Server (temporal tables, uložené procedury v T-SQL, plné nástroje SQL Serveru) a pro cokoli, co se může později přesunout na placenou edici SQL Serveru nebo Azure SQL. Jeho limity jsou skutečné: každá databáze je omezená na 10 GB dat, buffer pool zhruba na 1 410 MB a výpočetní výkon na menší z jednoho socketu nebo čtyř jader, bez SQL Server Agenta pro plánované úlohy. Hosting SQL Server Express popisuje, kdy to stačí.
PostgreSQL je výchozí doporučení pro nový projekt bez dalších omezení: žádné limity edic, výborná podpora JSON, bohaté indexování a Npgsql je prvotřídní. Vzdálená připojení k PostgreSQL popisuje první připojení.
MySQL je z těch tří nejlehčí na provoz a téměř každému povědomé. Je to dobrá volba, když na ni aplikace už míří nebo sdílí databázi se softwarem v PHP.
Delší srovnání, včetně MongoDB a Valkey, najdeš v článku kterou databázi použít.
Na RE:NODE je každá z nich samostatný databázový plán s přihlašovacími údaji generovanými pro každý server, dostupný na hostiteli a portu plánu: PostgreSQL od 6 $ měsíčně, MySQL 8.4 LTS od 4 $ s vygenerovaným heslem root, aplikační databází a aplikačním uživatelem a SQL Server 2022 Express od 6 $ s heslem sa a databází vytvořenou a nastavenou jako výchozí pro sa. Databázové plány nemají slot pro proxy - aplikace se připojuje přímo na hostitele a port. Plány aplikací C# / .NET zahrnují také vlastní sloty pro databáze, vytvářené v panelu s vygenerovaným hostitelem, uživatelem a heslem.
Řešení potíží#
`A network-related or instance-specific error occurred` (SQL Server). Špatný hostitel nebo port, dvojtečka místo čárky před portem, nebo firewall. Nejdřív otestuj port.
`The certificate chain was issued by an authority that is not trusted` (SQL Server). Šifrování je zapnuté ve výchozím stavu a certifikát serveru je self-signed. Přidej TrustServerCertificate=True nebo nainstaluj certifikát od důvěryhodné CA.
`Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool`. Spojení unikají nebo se drží příliš dlouho. Hledej kontexty nebo spojení vytvořená mimo using a práci prováděnou uvnitř otevřených transakcí.
`53300: sorry, too many clients already` (PostgreSQL) nebo `Too many connections` (MySQL). Pooly všech instancí tvé aplikace dohromady překračují limit serveru. Sniž Maximum Pool Size.
`Unable to connect to any of the specified MySQL hosts`. Hostitel, port nebo firewall. Pokud je hostitel správně, zkontroluj, jestli se uživatel smí připojit z tvé adresy.
FAQ#
Je Entity Framework Core pomalejší než Dapper?
U jednoduchých dotazů je moderní EF Core blízko, zejména s AsNoTracking() a projekcemi. Dapper pořád vyhrává v režii mapování a dává ti přesnou kontrolu nad SQL. Mnoho aplikací používá EF Core pro zápisy a migrace a Dapper pro pár náročných čtecích dotazů, nad stejným connection stringem.
Můžu v testech používat SQLite a v produkci SQL Server?
Můžeš a skryje to chyby: velikost písmen, práce s daty, chování transakcí i překlad SQL se liší. Spouštěj integrační testy proti stejnému enginu jako produkce, v případě potřeby v kontejneru.
Který provider pro MySQL mám s EF Core použít?
Pomelo nad MySqlConnector. Je nejrozšířenější a nejúplnější. Před povýšením EF Core ověř, že jeho vydání pro tvou major verzi EF Core existuje.
Potřebuju TLS mezi aplikací a databází?
Pokud spojení vede přes jakoukoli síť, kterou neovládáš - což zahrnuje internet mezi aplikačním a databázovým serverem - ano. Podporují ho všechny tři ovladače; ovladač SQL Serveru ho zapíná ve výchozím stavu.
Kolik spojení má můj pool povolit?
Méně, než si myslíš. Začni na dvaceti až třiceti na instanci aplikace u malé databáze, dohlédni, aby součet přes instance zůstal pod limitem databáze, a zvyšuj ho, jen když dokážeš, že požadavky čekají na pool, zatímco databáze sama nic nedělá.




Komentáře
Zcela anonymně: žádný účet, žádný e-mail, žádné cookie. Ukládáme jen jméno, které napíšeš, text a čas - nic dalšího. Počet odkazů je omezený a značkování se nevykresluje.