sql >> Databasteknik >  >> RDS >> MariaDB

Förbättra backend-prestanda Del 2/3:Använda databasindex

Databasindex är ett problem för utvecklarna. De har potential att förbättra prestandan för sök- och filterfunktioner som använder en SQL-fråga i backend. I den andra delen av den här artikelserien kommer jag att visa vilken inverkan ett databasindex har för att snabba upp filter med hjälp av en Java-webbapplikation utvecklad med Spring Boot och Vaadin.

Läs del 1 av den här serien om du vill lära dig hur exempelapplikationen som vi kommer att använda här fungerar. Du hittar koden på GitHub. Dessutom, och om du föredrar, spelade jag in en videoversion av den här artikeln:

Kravet

Vi har en webbsida med ett rutnät som visar en lista över böcker från en MariaDB-databas:

Vi vill lägga till ett filter så att användare av den här sidan kan se vilka böcker som publicerades vid ett givet datum.

Implementera arkivfrågan och tjänsten

Vi måste göra några ändringar i backend för att stödja filtrering av data efter publiceringsdatum. I repository-klassen kan vi lägga till följande metod:

@Repository
public interface BookRepository extends JpaRepository<Book, Integer> {

    Page<Book> findByPublishDate(LocalDate publishDate, Pageable pageable);

}

Detta använder lazy loading som vi såg i del 1 av denna artikelserie. Vi behöver inte implementera den här metoden – Spring Data skapar den åt oss vid körning.

Vi måste också lägga till en ny metod till serviceklassen (vilket är den klass som användargränssnittet använder för att köra affärslogik). Här är hur:

@Service
public class BookService {

    private final BookRepository repository;

    ...

    public Stream<Book> findAll(LocalDate publishDate, int page, int pageSize) {
        return repository.findByPublishDate(publishDate, PageRequest.of(page, pageSize)).stream();
    }

}

Lägga till ett filter på webbsidan

Med backend som stöder filtrering av böcker efter publiceringsdatum, kan vi lägga till en datumväljare till webbsidans (eller visa) implementeringen:

@Route("")
public class BooksView extends VerticalLayout {

    public BooksView(BookService service) {

        ...

        var filter = new DatePicker("Filter by publish date");
        filter.addValueChangeListener(event ->
                grid.setItems(query ->
                        service.findAll(filter.getValue(), query.getPage(), query.getPageSize())
                )
        );

        add(filter, grid);
        setSizeFull();
    }

    ...
}

Den här koden skapar bara en ny DatePicker objekt som lyssnar på förändringar i dess värde (via en värdeförändringslyssnare). När värdet ändras använder vi tjänsteklassen för att få böckerna publicerade på det datum som användaren valt. De matchande böckerna ställs sedan in som objekt i Grid .

Testa den långsamma frågan

Vi har implementerat filtret; dock är det extremt långsamt om du till exempel har 200 tusen rader i tabellen. Försök! Jag skrev en artikel som förklarar hur man genererar realistisk demodata för Java-applikationer. Med detta antal rader tog programmet flera sekunder att visa data på webbsidan på min maskin (MacBook Pro 2,3 GHz Quad-Core Intel Core i5). Detta förstör helt användarupplevelsen.

Analysera frågor med "Explain Query"

Om du aktiverade frågeloggning kan du hitta frågan som genereras av Hibernate i serverns logg. Kopiera det, ersätt frågetecknen med faktiska värden och kör det i en SQL-databasklient. Jag kan faktiskt spara lite tid. Här är en förenklad version av frågan:

SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';

MariaDB inkluderar EXPLAIN uttalande som ger oss användbar information om hur motorn uppskattar att frågan ska köras. För att använda det, lägg bara till EXPLAIN före frågan:

EXPLAIN SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';

Här är resultatet:

Dokumentationen har allt du behöver veta om det, men den viktiga biten är värdet i typen kolumn:ALLA . Detta värde talar om för oss att motorn uppskattar att den kommer att behöva hämta eller läsa alla rader i tabellen. Inte bra.

Skapa ett index

Lyckligtvis kan vi enkelt fixa detta genom att skapa ett index i kolumnen som vi använder för att filtrera data:publish_date . Här är hur:

CREATE INDEX book\_publish\_date_index ON book(publish_date);

Ett databasindex är en datastruktur skapad av motorn, vanligtvis ett b-träd (b för balanserad ), och det påskyndar processen att hitta en viss rad i en tabell, det vill säga att söka efter en rad givet värdet i kolumnen som indexet är byggt på. Processen är snabbare tack vare b-trädens natur – de håller data i ordning och reducerar tidskomplexiteten från O(N) till O(log(N)) och till och med O(log(1)) i vissa fall.

Testa förbättringen

Med indexet byggt kan vi köra EXPLAIN-satsen igen och se att typkolumnen visar värdet ref istället för ALLA :

ref värde betyder att motorn kommer att använda indexet när vi kör frågan. Det är viktigt att du kontrollerar detta när du lägger till index i dina mer komplexa frågor. Använd alltid EXPLAIN uttalande för att dubbelkolla att du vinner i prestanda när du introducerar ett index.

Om du provar webbapplikationen i webbläsaren och väljer ett annat datum i datumväljaren (du behöver inte starta om servern), kommer du att se en enorm skillnad! Till exempel hämtas data på mindre än en sekund på min maskin i motsats till flera sekunder innan vi skapade indexet!


  1. Lagring av krypterad data i Postgres

  2. SQLite trigger

  3. Hur man skapar en skrivskyddad användare i PostgreSQL

  4. Mer om introduktion av tidszoner i långlivade projekt