データベースインデックスは開発者の関心事です。これらは、バックエンドでSQLクエリを使用する検索およびフィルター機能のパフォーマンスを向上させる可能性があります。このシリーズの記事の第2部では、SpringBootとVaadinで開発されたJavaWebアプリケーションを使用して、データベースインデックスがフィルターの高速化に与える影響を示します。
ここで使用するサンプルアプリケーションがどのように機能するかを知りたい場合は、このシリーズのパート1をお読みください。コードはGitHubにあります。また、必要に応じて、この記事のビデオバージョンを録画しました:
要件
MariaDBデータベースの書籍のリストを表示するグリッド付きのWebページがあります:
このページのユーザーが特定の日に出版された本を確認できるように、フィルターを追加したいと思います。
リポジトリクエリとサービスの実装
公開日によるデータのフィルタリングをサポートするには、バックエンドにいくつかの変更を加える必要があります。リポジトリクラスに、次のメソッドを追加できます。
@Repository
public interface BookRepository extends JpaRepository<Book, Integer> {
Page<Book> findByPublishDate(LocalDate publishDate, Pageable pageable);
}
このシリーズの記事のパート1で見たように、これは遅延読み込みを使用します。このメソッドを実装する必要はありません。SpringDataによって実行時に作成されます。
また、サービスクラス(UIがビジネスロジックを実行するために使用するクラス)に新しいメソッドを追加する必要があります。方法は次のとおりです。
@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();
}
}
Webページへのフィルターの追加
公開日による書籍のフィルタリングをサポートするバックエンドを使用して、Webページ(またはビュー)の実装に日付ピッカーを追加できます。
@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();
}
...
}
このコードは、新しいDatePicker
を作成するだけです。 (値変更リスナーを介して)値の変更をリッスンするオブジェクト。値が変更されると、サービスクラスを使用して、ユーザーが選択した日に出版された本を取得します。一致する本は、Grid
のアイテムとして設定されます。 。
低速クエリのテスト
フィルタを実装しました。ただし、たとえば、テーブルに20万行ある場合は、非常に遅くなります。それを試してみてください! Javaアプリケーションの現実的なデモデータを生成する方法を説明する記事を書きました。この行数では、アプリケーションが私のマシン(MacBook Pro2,3GHzクアッドコアIntelCorei5)のWebページにデータを表示するのに数秒かかりました。これはユーザーエクスペリエンスを完全に台無しにします。
「ExplainQuery」を使用したクエリの分析
クエリログを有効にした場合、サーバーのログでHibernateによって生成されたクエリを見つけることができます。それをコピーし、疑問符を実際の値に置き換えて、SQLデータベースクライアントで実行します。実際、私はあなたに時間を節約することができます。クエリの簡略化されたバージョンは次のとおりです。
SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';
MariaDBにはEXPLAIN
が含まれています クエリを実行するエンジンをどのように推定するかについての有用な情報を提供するステートメント。使用するには、EXPLAIN
を追加するだけです。 クエリの前:
EXPLAIN SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';
結果は次のとおりです。
ドキュメントには、それについて知っておく必要のあるすべてのものが含まれていますが、重要なのはタイプの値です。 列:すべて 。この値は、エンジンがテーブル内のすべての行をフェッチまたは読み取る必要があると推定していることを示しています。良くないことです。
インデックスの作成
幸い、データのフィルタリングに使用している列にインデックスを作成することで、これを簡単に修正できます:publish_date
。方法は次のとおりです。
CREATE INDEX book\_publish\_date_index ON book(publish_date);
データベースインデックスは、エンジンによって作成されたデータ構造であり、通常はbツリー( b バランスの取れた )、これにより、テーブル内の特定の行を検索するプロセス、つまり、インデックスが作成されている列の値を指定して行を検索するプロセスが高速化されます。 Bツリーの性質のおかげで、プロセスは高速になります。データの順序付けが維持され、時間の複雑さがO(N)からO(log(N))、場合によってはO(log(1))にまで削減されます。
改善のテスト
インデックスが作成されたら、EXPLAINステートメントを再度実行して、タイプ列に値 refが表示されていることを確認できます。 すべての代わりに :
参照 valueは、クエリを実行するときにエンジンがインデックスを使用することを意味します。より複雑なクエリにインデックスを追加するときは、これを確認することが重要です。常にEXPLAIN
を使用してください インデックスを導入するときにパフォーマンスが向上していることを再確認するためのステートメント。
ブラウザでWebアプリケーションを試し、日付ピッカーで別の日付を選択すると(サーバーを再起動する必要はありません)、大きな違いがわかります。たとえば、インデックスを作成する前の数秒とは対照的に、私のマシンでは1秒未満でデータが取得されます!