読者です 読者をやめる 読者になる 読者になる

文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

s2jdbcはjoinが多い場合はentityへのマッピング処理が急激に遅くなる

seasar s2jdbc

s2jdbcで、JOIN数が多い場合の注意について。
プロジェクトも中盤、さあslow-query-logを元にSQLのパフォーマンスチューニングするか、という時、困った事が・・

public class Test1Service extends AbstractService<Test1> {
    public List<Test1> find(Integer param1) {
        return select().leftOuterJoin(Test1Names.test2()).leftOuterJoin(Test1Names.test3())
            .where(new SimpleWhereEx().eq(Test1Names.CTinyint(), param1)).getResultList();
    }
}

test1を親に、test2、test3を外部結合しています。さて、どのようにクエリが発行されたでしょうか。

select
T1_.C_TINYINT as C1_, T1_.C_SMALLINT as C2_, T1_.C_INT as C3_, T1_.C_MEDIUMINT as C4_, T1_.C_BIGINT as C5_, T1_.C_BOOLEAN as C6_, T1_.C_FLOAT as C7_, T1_.C_DOUBLE as C8_, T1_.C_DECIMAL as C9_, T1_.C_DATE as C10_, T1_.C_DATETIME as C11_, T1_.C_TIMESTAMP as C12_, T1_.C_TIME as C13_, T1_.C_YEAR as C14_, T1_.C_CHAR as C15_, T1_.C_VARCHAR as C16_, T1_.C_TINYTEXT as C17_, T1_.C_TEXT as C18_, T1_.C_MEDIUMTEXT as C19_, T1_.C_LONGTEXT as C20_, T1_.C_TINYBLOB as C21_, T1_.C_BLOB as C22_, T1_.C_MEDIUMBLOB as C23_, T1_.C_LONGBLOB as C24_, T1_.C_ENUM as C25_, T1_.C_SET as C26_, T2_.C_TINYINT as C27_, T2_.C_SMALLINT as C28_, T2_.C_INT as C29_, T2_.C_MEDIUMINT as C30_, T2_.C_BIGINT as C31_, T2_.C_BOOLEAN as C32_, T2_.C_FLOAT as C33_, T2_.C_DOUBLE as C34_, T2_.C_DECIMAL as C35_, T2_.C_DATE as C36_, T2_.C_DATETIME as C37_, T2_.C_TIMESTAMP as C38_, T2_.C_TIME as C39_, T2_.C_YEAR as C40_, T2_.C_CHAR as C41_, T2_.C_VARCHAR as C42_, T2_.C_TINYTEXT as C43_, T2_.C_TEXT as C44_, T2_.C_MEDIUMTEXT as C45_, T2_.C_LONGTEXT as C46_, T2_.C_TINYBLOB as C47_, T2_.C_BLOB as C48_, T2_.C_MEDIUMBLOB as C49_, T2_.C_LONGBLOB as C50_, T2_.C_ENUM as C51_, T2_.C_SET as C52_, T3_.C_TINYINT as C53_, T3_.C_SMALLINT as C54_, T3_.C_INT as C55_, T3_.C_MEDIUMINT as C56_, T3_.C_BIGINT as C57_, T3_.C_BOOLEAN as C58_, T3_.C_FLOAT as C59_, T3_.C_DOUBLE as C60_, T3_.C_DECIMAL as C61_, T3_.C_DATE as C62_, T3_.C_DATETIME as C63_, T3_.C_TIMESTAMP as C64_, T3_.C_TIME as C65_, T3_.C_YEAR as C66_, T3_.C_CHAR as C67_, T3_.C_VARCHAR as C68_, T3_.C_TINYTEXT as C69_, T3_.C_TEXT as C70_, T3_.C_MEDIUMTEXT as C71_, T3_.C_LONGTEXT as C72_, T3_.C_TINYBLOB as C73_, T3_.C_BLOB as C74_, T3_.C_MEDIUMBLOB as C75_, T3_.C_LONGBLOB as C76_, T3_.C_ENUM as C77_, T3_.C_SET as C78_
from TEST1 T1_ left outer join TEST2 T2_ on T2_.c_tinyint = T1_.c_tinyint left outer join TEST3 T3_ on T3_.c_tinyint = T1_.c_tinyint where (T1_.C_TINYINT = 1)

おおお・・・
JOINしたテーブルも含めた全テーブルの全カラムselectしてる・・・
実はこのs2jdbcですが、現状正規のやり方でselectするカラムを選択できません。
このサンプルではJOIN数は2テーブルだけですが、5〜10テーブルJOINしたらどうなるでしょう。
SQL自体は一瞬で結果が返ります。
しかし、問題はそこではなかった・・・・

SQLの結果セットをEntityのListにマッピングする処理が遅い!!
よくあるのが「なんかこのservice遅いよ?」とDBAに相談が行くが、serviceで実行するのではなく、mysqlclientでSQLを直に叩くと速い。
結局entityへのマッピングが遅いのでした。

この件を踏まえると、
JOIN数が多いか、多くなりそうな場合は最初からSQLファイルに手でSQLを書いた方がいい
ということになりますね。

もし前トピックのs2jdbcのSimpleWhereをカスタマイズする
whereが全削除されて全件selectされたら・・・・どうなるか解りますよね。

実践ハイパフォーマンスMySQL 第2版

実践ハイパフォーマンスMySQL 第2版