Java-app voor het verbinden en uitvoeren van SQL-opdrachten in Azure Cosmos DB for PostgreSQL
VAN TOEPASSING OP: Azure Cosmos DB for PostgreSQL (mogelijk gemaakt door de Citus-database-extensie naar PostgreSQL)
In deze quickstart ziet u hoe u Java-code gebruikt om verbinding te maken met een cluster en SQL-instructies gebruikt om een tabel te maken. Vervolgens voegt u gegevens in de database in, voert u query's uit, werkt u deze bij en verwijdert u deze. In de stappen in dit artikel wordt ervan uitgegaan dat u bekend bent met Java-ontwikkeling en JDBC en geen ervaring hebt met het werken met Azure Cosmos DB for PostgreSQL.
Het Java-project en de verbinding instellen
Maak een nieuw Java-project en een configuratiebestand om verbinding te maken met Azure Cosmos DB for PostgreSQL.
Een nieuw Java-project maken
Maak met uw favoriete IDE (Integrated Development Environment) een nieuw Java-project met groupId test
en artifactId crud
. Voeg in de hoofdmap van het project een pom.xml-bestand toe met de volgende inhoud. Dit bestand configureert Apache Maven voor het gebruik van Java 8 en een recent PostgreSQL-stuurprogramma voor Java.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>crud</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
</project>
Verbinding met de database configureren
Maak in src/main/resources/een bestand application.properties met de volgende inhoud. Vervang <het cluster> door de clusternaam en vervang het wachtwoord door <uw beheerderswachtwoord> of het Microsoft Entra ID-token.
driver.class.name=org.postgresql.Driver
db.url=jdbc:postgresql://c-<cluster>.<uniqueID>.postgres.cosmos.azure.com:5432/citus?ssl=true&sslmode=require
db.username=citus
db.password=<password>
De ?ssl=true&sslmode=require
tekenreeks in de db.url
eigenschap vertelt het JDBC-stuurprogramma dat tls (Transport Layer Security) moet gebruiken bij het maken van verbinding met de database. Het is verplicht OM TLS te gebruiken met Azure Cosmos DB for PostgreSQL en is een goede beveiligingspraktijk.
Tabellen maken
Configureer een databaseschema met gedistribueerde tabellen. Maak verbinding met de database om het schema en de tabellen te maken.
Het databaseschema genereren
Maak in src/main/resources/een schema.sql bestand met de volgende inhoud:
DROP TABLE IF EXISTS public.pharmacy;
CREATE TABLE public.pharmacy(pharmacy_id integer,pharmacy_name text ,city text ,state text ,zip_code integer);
CREATE INDEX idx_pharmacy_id ON public.pharmacy(pharmacy_id);
Tabellen distribueren
Azure Cosmos DB for PostgreSQL biedt u de superkracht van het distribueren van tabellen over meerdere knooppunten voor schaalbaarheid. Met de onderstaande opdracht kunt u een tabel distribueren. Hier vindt u meer informatie over create_distributed_table
en de distributiekolom.
Notitie
Als u tabellen distribueert, kunnen ze groeien over alle werkknooppunten die aan het cluster zijn toegevoegd.
Als u tabellen wilt distribueren, voegt u de volgende regel toe aan het schema.sql-bestand dat u in de vorige sectie hebt gemaakt.
select create_distributed_table('public.pharmacy','pharmacy_id');
Verbinding maken met de database en het schema maken
Voeg vervolgens de Java-code toe die gebruikmaakt van JDBC om gegevens op te slaan en op te halen uit uw cluster. De code maakt gebruik van de application.properties - en schema.sql-bestanden om verbinding te maken met het cluster en het schema te maken.
Maak een DButil.java-bestand met de volgende code, die de
DButil
klasse bevat. DeDBUtil
klasse stelt een verbindingsgroep in met PostgreSQL met behulp van HikariCP. U gebruikt deze klasse om verbinding te maken met PostgreSQL en query's uit te voeren.Tip
In de onderstaande voorbeeldcode wordt een verbindingsgroep gebruikt om verbindingen met PostgreSQL te maken en te beheren. Groepsgewijze verbindingen aan de toepassingszijde wordt sterk aanbevolen omdat:
- Het zorgt ervoor dat de toepassing niet te veel verbindingen met de database genereert en dus geen verbindingslimieten overschrijdt.
- Het kan helpen de prestaties drastisch te verbeteren, zowel latentie als doorvoer. Het PostgreSQL-serverproces moet fork gebruiken om elke nieuwe verbinding te verwerken en het hergebruik van een verbinding voorkomt die overhead.
//DButil.java package test.crud; import java.io.FileInputStream; import java.io.IOException; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import com.zaxxer.hikari.HikariDataSource; public class DButil { private static final String DB_USERNAME = "db.username"; private static final String DB_PASSWORD = "db.password"; private static final String DB_URL = "db.url"; private static final String DB_DRIVER_CLASS = "driver.class.name"; private static Properties properties = null; private static HikariDataSource datasource; static { try { properties = new Properties(); properties.load(new FileInputStream("src/main/java/application.properties")); datasource = new HikariDataSource(); datasource.setDriverClassName(properties.getProperty(DB_DRIVER_CLASS )); datasource.setJdbcUrl(properties.getProperty(DB_URL)); datasource.setUsername(properties.getProperty(DB_USERNAME)); datasource.setPassword(properties.getProperty(DB_PASSWORD)); datasource.setMinimumIdle(100); datasource.setMaximumPoolSize(1000000000); datasource.setAutoCommit(true); datasource.setLoginTimeout(3); } catch (IOException | SQLException e) { e.printStackTrace(); } } public static DataSource getDataSource() { return datasource; } }
Maak in src/main/java/een DemoApplication.java-bestand met de volgende code:
package test.crud; import java.io.IOException; import java.sql.*; import java.util.*; import java.util.logging.Logger; import java.io.FileInputStream; import java.io.FileOutputStream; import org.postgresql.copy.CopyManager; import org.postgresql.core.BaseConnection; import java.io.IOException; import java.io.Reader; import java.io.StringReader; public class DemoApplication { private static final Logger log; static { System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$-7s] %5$s %n"); log =Logger.getLogger(DemoApplication.class.getName()); } public static void main(String[] args)throws Exception { log.info("Connecting to the database"); Connection connection = DButil.getDataSource().getConnection(); System.out.println("The Connection Object is of Class: " + connection.getClass()); log.info("Database connection test: " + connection.getCatalog()); log.info("Creating table"); log.info("Creating index"); log.info("distributing table"); Scanner scanner = new Scanner(DemoApplication.class.getClassLoader().getResourceAsStream("schema.sql")); Statement statement = connection.createStatement(); while (scanner.hasNextLine()) { statement.execute(scanner.nextLine()); } log.info("Closing database connection"); connection.close(); } }
Notitie
De database
user
enpassword
referenties worden gebruikt bij het uitvoerenDriverManager.getConnection(properties.getProperty("url"), properties);
. De referenties worden opgeslagen in het bestand application.properties , dat als argument wordt doorgegeven.U kunt nu deze main-klasse uitvoeren met uw favoriete tool:
- Als u uw IDE gebruikt, moet u met de rechtermuisknop op de
DemoApplication
klasse kunnen klikken en deze uitvoeren. - Met Maven kunt u de toepassing uitvoeren door het volgende uit te voeren:
mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication"
.
- Als u uw IDE gebruikt, moet u met de rechtermuisknop op de
De toepassing moet verbinding maken met Azure Cosmos DB for PostgreSQL, een databaseschema maken en vervolgens de verbinding sluiten, zoals u in de consolelogboeken zou moeten zien:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Create database schema
[INFO ] Closing database connection
Een domeinklasse maken
Maak een nieuwe Java-klasse Pharmacy
, naast de klasse DemoApplication
, en voeg de volgende code toe:
public class Pharmacy {
private Integer pharmacy_id;
private String pharmacy_name;
private String city;
private String state;
private Integer zip_code;
public Pharmacy() { }
public Pharmacy(Integer pharmacy_id, String pharmacy_name, String city,String state,Integer zip_code)
{
this.pharmacy_id = pharmacy_id;
this.pharmacy_name = pharmacy_name;
this.city = city;
this.state = state;
this.zip_code = zip_code;
}
public Integer getpharmacy_id() {
return pharmacy_id;
}
public void setpharmacy_id(Integer pharmacy_id) {
this.pharmacy_id = pharmacy_id;
}
public String getpharmacy_name() {
return pharmacy_name;
}
public void setpharmacy_name(String pharmacy_name) {
this.pharmacy_name = pharmacy_name;
}
public String getcity() {
return city;
}
public void setcity(String city) {
this.city = city;
}
public String getstate() {
return state;
}
public void setstate(String state) {
this.state = state;
}
public Integer getzip_code() {
return zip_code;
}
public void setzip_code(Integer zip_code) {
this.zip_code = zip_code;
}
@Override
public String toString() {
return "TPharmacy{" +
"pharmacy_id=" + pharmacy_id +
", pharmacy_name='" + pharmacy_name + '\'' +
", city='" + city + '\'' +
", state='" + state + '\'' +
", zip_code='" + zip_code + '\'' +
'}';
}
}
Deze klasse is een domeinmodel dat is toegewezen aan de tabel Pharmacy
die u eerder hebt gemaakt tijdens het uitvoeren van het script schema.sql.
Gegevens invoegen
Voeg in het bestand DemoApplication.java , na de main
methode, de volgende methode toe die gebruikmaakt van de INSERT INTO SQL-instructie om gegevens in de database in te voegen:
private static void insertData(Pharmacy todo, Connection connection) throws SQLException {
log.info("Insert data");
PreparedStatement insertStatement = connection
.prepareStatement("INSERT INTO pharmacy (pharmacy_id,pharmacy_name,city,state,zip_code) VALUES (?, ?, ?, ?, ?);");
insertStatement.setInt(1, todo.getpharmacy_id());
insertStatement.setString(2, todo.getpharmacy_name());
insertStatement.setString(3, todo.getcity());
insertStatement.setString(4, todo.getstate());
insertStatement.setInt(5, todo.getzip_code());
insertStatement.executeUpdate();
}
Voeg de twee volgende regels toe in de hoofdmethode:
Pharmacy todo = new Pharmacy(0,"Target","Sunnyvale","California",94001);
insertData(todo, connection);
Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Creating table
[INFO ] Creating index
[INFO ] distributing table
[INFO ] Insert data
[INFO ] Closing database connection
Gegevens lezen
Lees de gegevens die u eerder hebt ingevoegd om te controleren of uw code correct werkt.
Voeg na de insertData
methode in het DemoApplication.java bestand de volgende methode toe die gebruikmaakt van de SELECT SQL-instructie om gegevens uit de database te lezen:
private static Pharmacy readData(Connection connection) throws SQLException {
log.info("Read data");
PreparedStatement readStatement = connection.prepareStatement("SELECT * FROM Pharmacy;");
ResultSet resultSet = readStatement.executeQuery();
if (!resultSet.next()) {
log.info("There is no data in the database!");
return null;
}
Pharmacy todo = new Pharmacy();
todo.setpharmacy_id(resultSet.getInt("pharmacy_id"));
todo.setpharmacy_name(resultSet.getString("pharmacy_name"));
todo.setcity(resultSet.getString("city"));
todo.setstate(resultSet.getString("state"));
todo.setzip_code(resultSet.getInt("zip_code"));
log.info("Data read from the database: " + todo.toString());
return todo;
}
Voeg de volgende regel toe in de hoofdmethode:
todo = readData(connection);
Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Creating table
[INFO ] Creating index
[INFO ] distributing table
[INFO ] Insert data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO ] Closing database connection
Gegevens bijwerken
Werk de gegevens bij die u eerder hebt ingevoegd.
Voeg na de methode, na de readData
methode, nog steeds in het DemoApplication.java-bestand de volgende methode toe om gegevens in de database bij te werken met behulp van de SQL-instructie UPDATE:
private static void updateData(Pharmacy todo, Connection connection) throws SQLException {
log.info("Update data");
PreparedStatement updateStatement = connection
.prepareStatement("UPDATE pharmacy SET city = ? WHERE pharmacy_id = ?;");
updateStatement.setString(1, todo.getcity());
updateStatement.setInt(2, todo.getpharmacy_id());
updateStatement.executeUpdate();
readData(connection);
}
Voeg de twee volgende regels toe in de hoofdmethode:
todo.setcity("Guntur");
updateData(todo, connection);
Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Creating table
[INFO ] Creating index
[INFO ] distributing table
[INFO ] Insert data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO ] Update data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO ] Closing database connection
Gegevens verwijderen
Verwijder ten slotte de gegevens die u eerder hebt ingevoegd. Voeg na de methode, na de updateData
methode, nog steeds in het DemoApplication.java-bestand de volgende methode toe om gegevens in de database te verwijderen met behulp van de SQL-instructie DELETE:
private static void deleteData(Pharmacy todo, Connection connection) throws SQLException {
log.info("Delete data");
PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM pharmacy WHERE pharmacy_id = ?;");
deleteStatement.setLong(1, todo.getpharmacy_id());
deleteStatement.executeUpdate();
readData(connection);
}
U kunt nu de volgende regel toevoegen in de hoofdmethode:
deleteData(todo, connection);
Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Creating table
[INFO ] Creating index
[INFO ] distributing table
[INFO ] Insert data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO ] Update data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO ] Delete data
[INFO ] Read data
[INFO ] There is no data in the database!
[INFO ] Closing database connection
COPY-opdracht voor snelle opname
De opdracht COPY kan een enorme doorvoer opleveren tijdens het opnemen van gegevens in Azure Cosmos DB for PostgreSQL. Met de opdracht COPY kunt u gegevens opnemen in bestanden of uit microbatches met gegevens in het geheugen voor realtime opname.
De opdracht COPY om gegevens uit een bestand te laden
Met de volgende code worden gegevens uit een CSV-bestand gekopieerd naar een databasetabel. Voor het codevoorbeeld is het bestand pharmacies.csv vereist.
public static long
copyFromFile(Connection connection, String filePath, String tableName)
throws SQLException, IOException {
long count = 0;
FileInputStream fileInputStream = null;
try {
Connection unwrap = connection.unwrap(Connection.class);
BaseConnection connSec = (BaseConnection) unwrap;
CopyManager copyManager = new CopyManager((BaseConnection) connSec);
fileInputStream = new FileInputStream(filePath);
count = copyManager.copyIn("COPY " + tableName + " FROM STDIN delimiter ',' csv", fileInputStream);
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return count;
}
U kunt nu de volgende regel toevoegen in de hoofdmethode:
int c = (int) copyFromFile(connection,"C:\\Users\\pharmacies.csv", "pharmacy");
log.info("Copied "+ c +" rows using COPY command");
Als u de main
klasse uitvoert, moet nu de volgende uitvoer worden geproduceerd:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Creating table
[INFO ] Creating index
[INFO ] distributing table
[INFO ] Insert data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO ] Update data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO ] Delete data
[INFO ] Read data
[INFO ] There is no data in the database!
[INFO ] Copied 5000 rows using COPY command
[INFO ] Closing database connection
COPY-opdracht voor het laden van in-memory gegevens
Met de volgende code worden gegevens in het geheugen gekopieerd naar een tabel.
private static void inMemory(Connection connection) throws SQLException,IOException
{
log.info("Copying inmemory data into table");
final List<String> rows = new ArrayList<>();
rows.add("0,Target,Sunnyvale,California,94001");
rows.add("1,Apollo,Guntur,Andhra,94003");
final BaseConnection baseConnection = (BaseConnection) connection.unwrap(Connection.class);
final CopyManager copyManager = new CopyManager(baseConnection);
// COPY command can change based on the format of rows. This COPY command is for above rows.
final String copyCommand = "COPY pharmacy FROM STDIN with csv";
try (final Reader reader = new StringReader(String.join("\n", rows))) {
copyManager.copyIn(copyCommand, reader);
}
}
U kunt nu de volgende regel toevoegen in de hoofdmethode:
inMemory(connection);
Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:
[INFO ] Loading application properties
[INFO ] Connecting to the database
[INFO ] Database connection test: citus
[INFO ] Creating table
[INFO ] Creating index
[INFO ] distributing table
[INFO ] Insert data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO ] Update data
[INFO ] Read data
[INFO ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO ] Delete data
[INFO ] Read data
[INFO ] There is no data in the database!
5000
[INFO ] Copying in-memory data into table
[INFO ] Closing database connection
App-nieuwe poging voor mislukte databaseaanvragen
Het is soms mogelijk dat databaseaanvragen van uw toepassing mislukken. Dergelijke problemen kunnen zich voordoen in verschillende scenario's, zoals netwerkfouten tussen app en database, onjuist wachtwoord, enzovoort. Sommige problemen kunnen tijdelijk zijn en zichzelf binnen enkele seconden tot minuten oplossen. U kunt logica voor opnieuw proberen in uw app configureren om de tijdelijke fouten op te lossen.
Het configureren van logica voor opnieuw proberen in uw app helpt de eindgebruikerservaring te verbeteren. In scenario's met fouten wachten gebruikers slechts wat langer totdat de toepassing aanvragen verwerkt, in plaats van fouten te ervaren.
In het onderstaande voorbeeld ziet u hoe u logica voor opnieuw proberen implementeert in uw app. Het voorbeeldcodefragment probeert elke 60 seconden (maximaal vijf keer) een databaseaanvraag uit te voeren totdat dit lukt. Het aantal en de frequentie van nieuwe pogingen kunnen worden geconfigureerd op basis van de behoeften van uw toepassing.
Vervang in deze code het cluster> door <uw clusternaam en <wachtwoord> door het beheerderswachtwoord.
package test.crud;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.logging.Logger;
import com.zaxxer.hikari.HikariDataSource;
public class DemoApplication
{
private static final Logger log;
static
{
System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$-7s] %5$s %n");
log = Logger.getLogger(DemoApplication.class.getName());
}
private static final String DB_USERNAME = "citus";
private static final String DB_PASSWORD = "<password>";
private static final String DB_URL = "jdbc:postgresql://c-<cluster>.<uniqueID>.postgres.cosmos.azure.com:5432/citus?sslmode=require";
private static final String DB_DRIVER_CLASS = "org.postgresql.Driver";
private static HikariDataSource datasource;
private static String executeRetry(String sql, int retryCount) throws InterruptedException
{
Connection con = null;
PreparedStatement pst = null;
ResultSet rs = null;
for (int i = 1; i <= retryCount; i++)
{
try
{
datasource = new HikariDataSource();
datasource.setDriverClassName(DB_DRIVER_CLASS);
datasource.setJdbcUrl(DB_URL);
datasource.setUsername(DB_USERNAME);
datasource.setPassword(DB_PASSWORD);
datasource.setMinimumIdle(10);
datasource.setMaximumPoolSize(1000);
datasource.setAutoCommit(true);
datasource.setLoginTimeout(3);
log.info("Connecting to the database");
con = datasource.getConnection();
log.info("Connection established");
log.info("Read data");
pst = con.prepareStatement(sql);
rs = pst.executeQuery();
StringBuilder builder = new StringBuilder();
int columnCount = rs.getMetaData().getColumnCount();
while (rs.next())
{
for (int j = 0; j < columnCount;)
{
builder.append(rs.getString(j + 1));
if (++j < columnCount)
builder.append(",");
}
builder.append("\r\n");
}
return builder.toString();
}
catch (Exception e)
{
Thread.sleep(60000);
System.out.println(e.getMessage());
}
}
return null;
}
public static void main(String[] args) throws Exception
{
String result = executeRetry("select 1", 5);
System.out.print(result);
}
}
Volgende stappen
- Bekijk hoe de Azure Cosmos DB for PostgreSQL-API PostgreSQL uitbreidt en nuttige diagnostische query's probeert uit te proberen
- Kies de beste clustergrootte voor uw workload
- Cluster-prestaties bewaken