DBインデックスの利用
DBインデックスとは?
DBインデックスは,データベースの記憶領域をさらに利用し,テーブルの探索速度を向上させるためのデータ構造である.索引は翻訳して索引を残すという意味です.
これは,本の中で特定のキーワードがどのページにあるかを調べるときに見られるインデックスページと同じ原理であると考えられる.
インデックス・ページを表示すると、本の中で検索する内容のページを見つけることができます.DBインデックスを使用すると、テーブルの実行速度を速め、データをすばやく検索できます.
インデックスは良い方法です.
SQLはwhereセクションに影響します.
通常、検索時にプライマリ・キー「Id」を使用して検索する以外は(プライマリ・キーとして指定すると、一意のunclusted indexが自動的に生成されます).
select * from 'student' where 'student_name' = 'John Kim'
JPA query method: findAllByStudentName(String name)
上記のクエリー検索のように、特定のコラムを使用して検索することもできます.対応するコラム「student name」にインデックスを付けると、パフォーマンスが向上します.
なぜなら、インデックスに入ると、データが入る順序で完全なスキャンを行うのではなく、その場所を迅速に見つけることができるからです.同様の意味であるが、技術的には、インデックスのコラムは、クエリ要求時にO(n)の通常のスキャン速度よりも速いO(logn)のB−tree方式でスキャンすることができる.
プロジェクトに適用
現在のthandbagプロジェクトでは、JPAがデフォルトで提供するqueryメソッドに加えて、生成されるカスタムqueryメソッドは次のようになります.
Page<Alarm> findAllByUserIdOrderByIdDesc(Long userId, Pageable pageable);
void deleteAllByPostId(Long postId);
Optional<ChatContent> findFirstByChatRoomOrderByCreatedAtDesc(ChatRoom chatRoom);
List<ChatContent> findAllByChatRoomOrderByCreatedAtAsc(ChatRoom room);
List<ChatContent> findAllByUserNotAndChatRoomAndIsRead(User user, ChatRoom chatRoom, Boolean isRead);
List<ChatRoom> findAllByPubUserIdOrSubUserId(Long id, Long id2);
ChatRoom findByPubUserIdAndSubUserId(Long id, Long id2);
Boolean existsAllByPubUserIdAndSubUserId(Long id, Long id2);
CommentLike findByUserIdAndComment(long userId, Comment comment);
List<CommentLike> findAllByComment(Comment comment);
boolean existsByCommentAndUserId(Comment comment, Long userId);
@Query(value = "select p from Post p where p.share = true and (p.title like %:keyword% or p.content like %:keyword% or p.user in (select u from User u where u.nickname like %:keyword%))")
Page<Post> findAllByShareTrueAndContainsKeywordForSearch(@Param("keyword") String keyword, Pageable pageable);
List<Post> findAllByUser(User user);
Page<Post> findAllByUserOrderByCreatedAtDesc(User user, Pageable pageable);
Page<Post> findAllByShareTrueOrderByCreatedAtDesc(Pageable pageable);
List<Post> findAllByShareTrueOrderByCreatedAtDesc();
Optional<User> findByUsername(String username);
Optional<User> findByNickname(String nickname);
Optional<User> findByKakaoId(Long kakaoId);
このうち,インデックスに適したqueryメソッドとしては,以下の2つが考えられる.Optional<User> findByUsername(String username);
Optional<User> findByNickname(String nickname);
検索クエリーでは、完全なスキャンが必要なため、インデックスは必要ありません. @Query(value = "select p from Post p where p.share = true and (p.title like %:keyword% or p.content like %:keyword% or p.user in (select u from User u where u.nickname like %:keyword%))")
Page<Post> findAllByShareTrueAndContainsKeywordForSearch(@Param("keyword") String keyword, Pageable pageable);
次のクエリ・メソッドは、重複値が多すぎるため、基数または選択性の面で有効ではないと判断して除外されます. List<ChatRoom> findAllByPubUserIdOrSubUserId(Long id, Long id2);
ChatRoom findByPubUserIdAndSubUserId(Long id, Long id2);
Boolean existsAllByPubUserIdAndSubUserId(Long id, Long id2);
Optional<User> findByKakaoId(Long kakaoId);
次のクエリは外部キーとして参照され、インデックスは生成され、除外されます. List<CommentLike> findAllByComment(Comment comment);
boolean existsByCommentAndUserId(Comment comment, Long userId);
Optional<ChatContent> findFirstByChatRoomOrderByCreatedAtDesc(ChatRoom chatRoom);
List<ChatContent> findAllByChatRoomOrderByCreatedAtAsc(ChatRoom room);
List<ChatContent> findAllByUserNotAndChatRoomAndIsRead(User user, ChatRoom chatRoom, Boolean isRead);
次の2つのクエリーは、主に私のページで有効性チェックやニックネームの変更に使用されます. Optional<User> findByUsername(String username);
Optional<User> findByNickname(String nickname);
Insertに比べてselectやupdate構文が発生する回数が多いため、使用率の観点から「username」や「nickname」はインデックス化に適しており、以下に示すようにします.@Entity
@Table(indexes = {@Index(name = "n_index", columnList = "nickname", unique = true),
@Index(name = "u_index", columnList = "username", unique = true)})
public class User extends Timestamped {
インデックス・パフォーマンスのテスト
まだサービスが始まっていないので会員数が足りないので、バーチャルデータを入れてjmeterで性能テストを行いました.
1号試験環境
MySQLでは、一意のユーザー名と一意のニックネームを合計1000個作成したユーザーデータ
毎秒10名の会員が同時に自分のニックネームを変更します
2番目のテスト環境
H 2で作成されたユーザデータの合計10,000個の一意のユーザ名と一意のニックネーム
毎秒10名の会員が同時に自分のニックネームを変更します
1号試験環境結果
インデックスが作成されていません
インデックスが作成されている場合:
1番のテストの結果、データ量が少ないためかスループットと平均に大きな差はなかったが、99%の回線で212->150の効率が30%以上に達した.
2番目のテスト環境の結果
インデックスが作成されていません
インデックスが作成されている場合:
10000個のデータでテストを行い、全行程の差は4倍近くあった.
注意:
https://yurimkoo.github.io/db/2020/03/14/db-index.html
https://youngwonhan-family.tistory.com/86
Reference
この問題について(DBインデックスの利用), 我々は、より多くの情報をここで見つけました https://velog.io/@davidko/DB-index-활용テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol