Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek vysvětluje, jak připravené parametry příkazu ovlivňují výkon na straně serveru v ovladači Microsoft JDBC pro SQL Server a poskytuje pokyny k optimalizaci využití parametrů.
Vysvětlení parametrů připravených příkazů
Připravené příkazy nabízejí významné výhody výkonu tím, že SQL Serveru umožní analyzovat, kompilovat a optimalizovat dotaz jednou a pak opakovaně použít plán provádění. Způsob, jakým zadáte parametry, ale může výrazně ovlivnit tuto výhodu výkonu.
Když vytvoříte připravený příkaz, SQL Server vygeneruje plán provádění na základě metadat parametrů, včetně:
- Datový typ
- Přesnost (pro číselné typy)
- Měřítko (pro desetinné typy)
- Maximální délka (pro řetězcové a binární typy)
Tato metadata jsou zásadní, protože SQL Server ho používá k optimalizaci plánu provádění dotazů. Změny některé z těchto charakteristik parametrů můžou vynutit, aby SQL Server zahodil existující plán a vytvořil nový, což má za následek snížení výkonu.
Vliv změn parametrů na výkon
Změny typu parametru
Když se mezi spuštěními změní typ parametru připraveného příkazu, sql Server musí příkaz znovu připravit. Tato opětovná příprava zahrnuje:
- Opětovná analýza příkazu SQL
- Kompilace nového plánu provádění
- Ukládání nového plánu do mezipaměti (pokud je povoleno ukládání do mezipaměti).
Představte si následující příklad:
String sql = "SELECT * FROM Employees WHERE EmployeeID = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
// First execution with Integer
pstmt.setInt(1, 100);
pstmt.executeQuery();
// Second execution with String - causes re-preparation
pstmt.setString(1, "100");
pstmt.executeQuery();
V tomto scénáři přepnutím z setInt na setString se změní typ parametru z int na varchar, což přinutí SQL Server znovu připravit příkaz.
Změny přesnosti a škálování
U číselných typů jako decimal a numericzměny přesnosti nebo škálování také aktivují opětovné přípravy:
String sql = "UPDATE Products SET Price = ? WHERE ProductID = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
// First execution with specific precision
BigDecimal price1 = new BigDecimal("19.99"); // precision 4, scale 2
pstmt.setBigDecimal(1, price1);
pstmt.setInt(2, 1);
pstmt.executeUpdate();
// Second execution with different precision - causes re-preparation
BigDecimal price2 = new BigDecimal("1999.9999"); // precision 8, scale 4
pstmt.setBigDecimal(1, price2);
pstmt.setInt(2, 2);
pstmt.executeUpdate();
SQL Server vytváří různé plány provádění pro různé kombinace přesnosti a škálování, protože přesnost a škálování ovlivňují, jak databázový stroj zpracovává dotaz.
Osvědčené postupy pro použití parametrů
Pokud chcete maximalizovat výkon připravených příkazů, postupujte podle těchto osvědčených postupů:
Explicitní zadání typů parametrů
Pokud je to možné, použijte explicitní metody setter, které odpovídají typům sloupců databáze:
// Good: Explicit type matching
pstmt.setInt(1, employeeId);
pstmt.setString(2, name);
pstmt.setBigDecimal(3, salary);
// Avoid: Using setObject() without explicit types
pstmt.setObject(1, employeeId); // Type inference might vary
Použití konzistentních metadat parametrů
Zachování konzistentní přesnosti a měřítka pro číselné parametry:
// Good: Consistent precision and scale
BigDecimal price1 = new BigDecimal("19.99").setScale(2);
BigDecimal price2 = new BigDecimal("29.99").setScale(2);
// Avoid: Varying precision and scale
BigDecimal price3 = new BigDecimal("19.9"); // scale 1
BigDecimal price4 = new BigDecimal("29.999"); // scale 3
Principy zaokrouhlení dat pomocí číselných typů
Použití nesprávné přesnosti a škály číselných parametrů může vést k nezamýšleným zaokrouhlením dat. Přesnost a měřítko musí být vhodné jak pro hodnotu parametru, tak pro místo, kde se používá v příkazu SQL.
// Example: Column defined as DECIMAL(10, 2)
// Good: Matching precision and scale
BigDecimal amount = new BigDecimal("12345.67").setScale(2, RoundingMode.HALF_UP);
pstmt.setBigDecimal(1, amount);
// Problem: Scale too high causes rounding
BigDecimal amount2 = new BigDecimal("12345.678"); // scale 3
pstmt.setBigDecimal(1, amount2); // Rounds to 12345.68
// Problem: Precision too high
BigDecimal amount3 = new BigDecimal("123456789.12"); // Exceeds precision
pstmt.setBigDecimal(1, amount3); // Might cause truncation or error
I když potřebujete odpovídající přesnost a škálování dat, vyhněte se změnám těchto hodnot pro každé spuštění připraveného příkazu. Každá změna přesnosti nebo škálování způsobí, že se příkaz znovu připraví na serveru a neguje výhody výkonu připravených příkazů.
// Good: Consistent precision and scale across executions
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO Orders (OrderID, Amount) VALUES (?, ?)");
for (Order order : orders) {
pstmt.setInt(1, order.getId());
// Always use scale 2 for currency
BigDecimal amount = order.getAmount().setScale(2, RoundingMode.HALF_UP);
pstmt.setBigDecimal(2, amount);
pstmt.executeUpdate();
}
// Avoid: Changing scale for each execution
for (Order order : orders) {
pstmt.setInt(1, order.getId());
// Different scale each time - causes re-preparation
pstmt.setBigDecimal(2, order.getAmount()); // Variable scale
pstmt.executeUpdate();
}
Vyvážení správnosti a výkonu:
- Určete odpovídající přesnost a škálování pro vaše obchodní požadavky.
- Normalizujte všechny hodnoty parametrů, aby měly konzistentní přesnost a měřítko.
- Pomocí explicitních režimů zaokrouhlení můžete řídit, jak se hodnoty upraví.
- Ověřte, že normalizované hodnoty odpovídají definicům cílového sloupce.
Poznámka:
Pomocí možnosti připojení calcBigDecimalPrecision můžete automaticky optimalizovat přesnost parametrů. Pokud je tato možnost povolená, ovladač vypočítá minimální přesnost potřebnou pro každou hodnotu BigDecimal, což pomáhá vyhnout se zbytečnému zaokrouhlení. Tento přístup ale může způsobit častější přípravy příkazů, jakmile se data změní, protože různé hodnoty přesnosti mohou vést k opětovné přípravě. Ruční definování optimální přesnosti a škálování v kódu aplikace je nejlepší v případě potřeby, protože poskytuje přesnost dat i konzistentní opakované použití příkazů.
Vyhněte se kombinování metod nastavení parametrů
Nepřepínejte mezi různými metodami setter pro stejnou pozici parametru napříč prováděními:
// Avoid: Mixing setter methods
pstmt.setInt(1, 100);
pstmt.executeQuery();
pstmt.setString(1, "100"); // Different method - causes re-preparation
pstmt.executeQuery();
Použití setNull() s jejími explicitními typy
Při nastavování hodnot null zadejte typ SQL pro zachování konzistence:
// Good: Explicit type for null
pstmt.setNull(1, java.sql.Types.INTEGER);
// Avoid: Generic null without type
pstmt.setObject(1, null); // Type might be inferred differently
Monitorování výkonu souvisejícího s parametry
Zjišťování problémů s opětovnou přípravou
Pokud chcete zjistit, jestli změny parametrů způsobují problémy s výkonem:
- K monitorování událostí
SP:CacheMissaSP:Recompilepoužijte SQL Server Profiler nebo rozšířené události. -
sys.dm_exec_cached_plansZkontrolujte zobrazení dynamické správy a zkontrolujte opakované použití plánu. - Analyzujte metriky výkonu dotazů a identifikujte příkazy s častou přepracovatelností.
Příklad dotazu pro kontrolu opakovaného použití plánu:
SELECT
text,
usecounts,
size_in_bytes,
cacheobjtype,
objtype
FROM sys.dm_exec_cached_plans AS cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS st
WHERE text LIKE '%YourQueryText%'
ORDER BY usecounts DESC;
Čítače výkonu
Monitorujte tyto čítače výkonu SQL Serveru:
- Statistika SQL: Opakované kompilace SQL za sekundu – ukazuje, jak často se příkazy rekompilují.
- Statistika SQL: Kompilace SQL za sekundu – ukazuje, jak často se vytvářejí nové plány.
- Mezipaměť plánů: Poměr přístupů do mezipaměti – označuje, jak efektivně se plány znovu používají.
Další podrobnosti o čítačích a jejich interpretaci naleznete v tématu SQL Server, Plan Cache objekt.
Pokročilé aspekty
Parametrizované dotazy a znečištění mezipaměti plánů
K znečištění vyrovnávací paměti plánu dochází, když různá desetinná nebo číselná přesnost způsobí, že SQL Server vytvoří pro stejný dotaz více výkonových plánů. Tento problém ztrácí paměť a snižuje efektivitu opakovaného použití plánu:
// Avoid: Varying precision pollutes the plan cache
String sql = "UPDATE Products SET Price = ? WHERE ProductID = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
for (int i = 0; i < 1000; i++) {
// Each different precision/scale creates a separate cached plan
BigDecimal price = new BigDecimal("19." + i); // Varying scale
pstmt.setBigDecimal(1, price);
pstmt.setInt(2, i);
pstmt.executeUpdate();
}
pstmt.close();
Abyste se vyhnuli znečištění plánové mezipaměti, udržujte konzistentní přesnost a škálu pro numerické parametry:
// Good: Consistent precision and scale enables plan reuse
String sql = "UPDATE Products SET Price = ? WHERE ProductID = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
for (int i = 0; i < 1000; i++) {
// Same precision and scale - reuses the same cached plan
// Note: Round or increase to a consistent scale that aligns with your application data needs.
BigDecimal price = new BigDecimal("19." + i).setScale(2, RoundingMode.HALF_UP);
pstmt.setBigDecimal(1, price);
pstmt.setInt(2, i);
pstmt.executeUpdate();
}
pstmt.close();
Varianty délky řetězců a celočíselných hodnot nezpůsobují znečištění mezipaměti plánu – tento problém vytvářejí pouze změny přesnosti a škálování číselných typů.
Vlastnosti připojovacího řetězce
Ovladač JDBC poskytuje vlastnosti připojení, které ovlivňují chování a výkon připravených příkazů:
-
enablePrepareOnFirstPreparedStatementCall – (Default:
false) Řídí, zda ovladač volásp_prepexecpři prvním nebo druhém spuštění. Příprava na první spuštění mírně zvyšuje výkon, pokud aplikace konzistentně provádí stejný připravený příkaz několikrát. Příprava na druhé spuštění zlepšuje výkon aplikací, které většinou spouští připravené příkazy jednou. Tato strategie eliminuje potřebu samostatného volání pro zrušení přípravy, pokud je připravený příkaz proveden pouze jednou. -
prepareMethod - (Výchozí:
prepexec) Určuje chování, které se má použít pro přípravu (prepareneboprepexec). NastaveníprepareMethodnapreparezpůsobí samostatný, počáteční dotaz do databáze za účelem přípravy příkazu bez jakýchkoliv počátečních hodnot pro zvážení v plánu provádění. Nastavte naprepexec, aby sesp_prepexecpoužila jako metoda přípravy. Tato metoda kombinuje akci přípravy s prvním spuštěním, čímž se snižuje počet cestování po síti. Poskytuje také databázi s počátečními hodnotami parametrů, které může databáze zvážit v plánu provádění. V závislosti na tom, jak jsou indexy optimalizované, může jedno nastavení fungovat lépe než druhé. -
serverPreparedStatementDiscardThreshold – (Výchozí:
10) Řídí dávkovánísp_unprepareoperací. Tato možnost může zvýšit výkon tím, že seskupí volání dohromady.sp_unprepareVyšší hodnota ponechá připravené příkazy na serveru delší dobu.
Další informace naleznete v tématu Nastavení vlastností připojení.
Shrnutí
Optimalizování výkonu připravených příkazů pro parametry:
- Použijte explicitní metody setter, které odpovídají typům sloupců databáze.
- Zachovejte metadata parametrů (typ, přesnost, měřítko, délku) konzistentní napříč prováděními.
- Nepřepínejte mezi různými metodami setter pro stejný parametr.
- Explicitně zadejte typy SQL při použití
setObjectnebosetNull. - Opakovaně používejte připravené příkazy místo vytváření nových příkazů.
- Monitorujte statistiky mezipaměti plánu a identifikujte problémy s opětovnou přípravou.
- Zvažte vlastnosti připojení, které ovlivňují výkon připravených příkazů.
Dodržováním těchto postupů minimalizujete opětovnou přípravu na straně serveru a získáte z připravených příkazů maximální výhody z výkonu.
Viz také
Ukládání metadat připravených příkazů do mezipaměti pro ovladač JDBC
zvýšení výkonu a spolehlivosti pomocí ovladače JDBC
Nastavení vlastností připojení