23 Nisan 2023 Pazar

Page Yapısı

Giriş
Açıklaması şöyle
In a row-store database engine, rows are stored in units called pages. Each page has a fixed header and contains multiple rows, with each row having a record header followed by its respective columns.
Şeklen şöyle

Dosya Sistemi
Page yapısı ile dosya sisteminin block yapısı birbiri ile uyumlu olmayabilir. Şeklen şöyle


Buffer pool
Açıklaması şöyle
Buffer pool is a shared memory space between all the database processes where the pages are kept, the pages can also receives writes there too.



Index Only Scans - SELECT ve WHERE İçinde Sadece Index'li Sütun Var

Giriş
Açıklaması şöyle
Index Only scans are very similar to index scans except that they scan only the indexes and do not touch the table data. This is possible only if the query contains the indexed column in both the SELECT and WHERE clauses
SELECT *
Açıklaması şöyle. Yani SELECT * varsa Index Only Scan olamaz
Using SELECT * means that the database optimizer cannot choose index-only scans. For example, let’s say you need the IDs of students who scored above 90, and you have an index on the grades column that includes the student ID as a non-key, this index is perfect for this query.

However, since you asked for all fields, the database needs to access the heap data page to get the remaining fields increasing random reads resulting in far more I/Os. In contrast, the database could have only scanned the grades index and returned the IDs if you hadn’t used SELECT *.
Etkisiz Kılmak
Açıklaması şöyle
# To disable the index on session level run below query.
set enable_indexscan TO OFF;
Kullanım
Örnek
Şöyle yaparız. Burada id alanı için indeks yaratılıyor
CREATE INDEX id_idx ON fake_data USING BTREE(id);
Sorgu içinde sadece id alanını çekeriz şöyle yaparız
EXPLAIN ANALYZE SELECT id FROM fake_data WHERE 
 fake_data.id = 1000;
Örnek
Şöyle yaparız. Burada select içinde indeks sütunu ismi geçmiyor ama COUNT(*) aynı anlama geliyor. WHERE koşulunda da sadece indekslenmiş alan var.
> CREATE TABLE grades(id SERIAL NOT NULL, g INT NOT NULL);
> CREATE INDEX grades_index ON grades(g);

> EXPLAIN ANALYZE SELECT COUNT(*) FROM grades  WHERE g=30;
   QUERY PLAN                                                                
-----------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=231.09..231.09 rows=1 width=8) (actual time=4.709..4.711 rows=1 loops=1)
   ->  Index Only Scan using grades_index on grades  (cost=0.42..206.75 rows=9733 width=0) (actual time=0.052..3.322 rows=10038 loops=1)
         Index Cond: (g = 30)
         Heap Fetches: 0
 Planning Time: 0.207 ms
 Execution Time: 4.774 ms

6 Nisan 2023 Perşembe

JDBC PGXADataSource Sınıfı

Giriş
Şu satırı dahil ederiz
import org.postgresql.xa.PGXADataSource;
PGSimpleDataSource yazısına bakılabilir

Örnek
Şöyle yaparız
import org.postgresql.ds.common.BaseDataSource;

PostgreSQLContainer container = ...;

BaseDataSource dataSource = new PGXADataSource();
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
dataSource.setDatabaseName(container.getDatabaseName());

5 Nisan 2023 Çarşamba

Testcontainers PostgreSQLContainer Sınıfı

Giriş
Şu satırı dahil ederiz
import org.testcontainers.containers.PostgreSQLContainer;
Üç tane bağımlılık gerekiyor. Açıklaması şöyle
1. org.testcontainers:testcontainers
includes core packages.
2. org.testcontainers:postgresql
includes PostgreSQL-specific packages. This dependency depends on database which your application is using. You will find the list of supported databases here.
3. org.testcontainers:junit-jupiter
integrates JUnit with Testcontainers.
Maven
Şu satırı dahil ederiz
<properties>
  <testcontainers.version>1.16.0</testcontainers.version>
</properties>

<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>junit-jupiter</artifactId>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>postgresql</artifactId>
  <scope>test</scope>
</dependency>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>testcontainers-bom</artifactId>
      <version>${testcontainers.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
Gradle
Şöyle yaparız
dependencies {
 ...
 testImplementation 'org.testcontainers:testcontainers'
 testImplementation 'org.testcontainers:postgresql' 
 testImplementation 'org.testcontainers:junit-jupiter'
 ...
}

dependencyManagement {
 imports {
  mavenBom "org.testcontainers:testcontainers-bom:1.17.6"
 }
}
1. DriverManager.getConnection İle Kullanımı
PostgreSQLContainer nesnesi yaratıldıktan sonra JDBC ile iş yapacaksak DriverManager nesnesini kullanarak JDBC Connection elde etmek lazım. 

Örnek - URL + UserName + Password
DriverManager.getConnection() çağrısına kullanıcı adı ve şifre geçeceksek şöyle yaparız
DockerImageName POSTGRES_IMAGE =
  DockerImageName.parse("debezium/example-postgres:1.7")
  .asCompatibleSubstituteFor("postgres");

PostgreSQLContainer container = new PostgreSQLContainer<>(POSTGRES_IMAGE)
  .withDatabaseName("postgres")
  .withUsername("postgres")
  .withPassword("postgres")
  .withConnectTimeoutSeconds(300)
  .withStartupTimeoutSeconds(300)
  .withStartupAttempts(5)
  .withCreateContainerCmdModifier(createContainerCmd -> {...})

container.start();

 try (Connection connection = DriverManager.getConnection(container.getJdbcUrl(), 
                                                          container.getUsername(),
                                                          container.getPassword())) {
  connection.setSchema("inventory");
  try (Statement statement = connection.createStatement()) {
    ...
  }
}
Örnek - URL İçinde UserName ve Password
Eğer DriverManager.getConnection() ile sadece URL kullanacaksak şöyle yapmak gerekiyor
String jdbcUrl = container.getJdbcUrl() + "&user=" + container.getUsername() +
                                  "&password=" + container.getPassword();
// Output
jdbc:postgresql://localhost:52135/test?loggerLevel=OFF&user=test&password=test

 2. PostgreSQLContainer Metodlar
Çok fazla metod var. Bazı örnekler aşağıda

getDriverClassName metodu
Örnek - Eski Spring Kodu
Şöyle yaparız.  Yeni Spring ile artık @DynamicPropertySource anotasyonuna gerek yok
@Testcontainers
@ContextConfiguration(classes = {PersistenceConfig.class})
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class StudentRepositoryJpaIT extends StudentRepositoryTest {

  @Container
  public static PostgreSQLContainer container = new PostgreSQLContainer("postgres:latest")
    .withDatabaseName("students_db")
    .withUsername("sa")
    .withPassword("sa");


  @DynamicPropertySource
  public static void overrideProperties(DynamicPropertyRegistry registry){
    registry.add("spring.datasource.url", container::getJdbcUrl);
    registry.add("spring.datasource.username", container::getUsername);
    registry.add("spring.datasource.password", container::getPassword);
    registry.add("spring.datasource.driver-class-name", container::getDriverClassName);
  }
  ...
}
getFirstMappedPort
Örnek
Şöyle yaparız
Integer hostPort = container.getFirstMappedPort();
getHost metodu
Örnek
Şöyle yaparız
String host = container.getHost()
getJdbcUrl metodu
Şöyle yaparız
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;

public class PostgresIntegrationTest {
  @Container
  private static final PostgreSQLContainer<?> postgresContainer =
    new PostgreSQLContainer<>("postgres:latest");

  @Test
  void testDatabaseConnection() {
    // Get database connection properties from the container instance
    String jdbcUrl = postgresContainer.getJdbcUrl();
    String username = postgresContainer.getUsername();
    String password = postgresContainer.getPassword();

    // Perform database tests using the connection properties
    // ...
  }
}
getMappedPort metodu
Açıklaması şöyle
You cannot choose which actual port is used on the host machine. TestContainers chooses one automatically and makes it accessible through getMappedPort(containerPort) method on the container instance. You can also use getFirstMappedPort() if you only have one.
Örnek
Şöyle yaparız
Integer hostPort = container.getMappedPort(8080);
Örnek
Şöyle yaparız. PostgreSQLContainer.POSTGRESQL_PORT değişkenin değeri 5432
Integer hostPort = container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT);
withCommand metodu
Örnek
Şöyle yaparız
public static PostgreSQLContainer container = new PostgreSQLContainer<>("postgres:12.1")
  .withCommand("postgres -c max_prepared_transactions=10")
  .withCommand("postgres -c max_connections=500");
Aynı şeyi şöyle yaparız
public static PostgreSQLContainer container = new PostgreSQLContainer<>("postgres:12.1")
  .withCommand("postgres -c max_prepared_transactions=10 -c max_connections=500");
withTmpFs metodu
Örnek
Şöyle yaparız. Burada PGDATA ortam değişkeni de /var/lib/postgresql/data olarak değiştiriliyor ama bence gerek yok. Çünkü varsayılan değer zaten böyle
var container = PostgreSQLContainer(postgresDockerImage)
  .withDatabaseName("dataBaseName")
  .withUsername("username")
  .withPassword("password")
  .withEnv(mapOf("PGDATA" to "/var/lib/postgresql/data"))
  .withTmpFs(mapOf("/var/lib/postgresql/data" to "rw"))

withUsername metodu
Şöyle yaparız
@Container
private static final PostgreSQLContainer<?> postgresContainer =
  new PostgreSQLContainer<>(DockerImageName.parse("postgres:latest"))
    .withDatabaseName("mydb")
    .withUsername("user")
    .withPassword("password");