GR8Conf 2011: GORM Optimization
Upcoming SlideShare
Loading in...5
×
 

GR8Conf 2011: GORM Optimization

on

  • 2,726 views

 

Statistics

Views

Total Views
2,726
Slideshare-icon Views on SlideShare
2,726
Embed Views
0

Actions

Likes
1
Downloads
54
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    GR8Conf 2011: GORM Optimization GR8Conf 2011: GORM Optimization Presentation Transcript

    • GORM OptimizationBurt BeckwithSpringSource CONFIDENTIAL © 2010 SpringSource, A division of VMware. All rights reserved
    • Agenda Mapping Database Views Writing a Custom Configuration Subclass for Fun and Profit Read-only Domain Classes Monitoring CONFIDENTIAL 2
    • Also See Advanced GORM - Performance, Customization and Monitoring • Spring One / class UserInfo { 2GX 2010 String name String orgName • http://www.infoq.com/presentations/GORM-Performance static mapping = { • Primarily focused on v_user_info table performance implications around } } using Many-to-One and Many-to-Many in GORM CONFIDENTIAL 3
    • Mapping Database Views CONFIDENTIAL 4
    • Database View –> Entity class Organization { String name } class UserInfo { String name String orgName } class AuthUser { String name String password Organization organization } CONFIDENTIAL 5
    • Database View –> Entity CREATE OR REPLACE VIEW v_user_info AS SELECT u.name, u.id, u.version, o.name org_name FROM auth_user u, organization o WHERE u.organization_id = o.id class UserInfo { String name String orgName static mapping = { table v_user_info } } CONFIDENTIAL 6
    • Database View –> Entity ERROR hbm2ddl.SchemaExport  ­  Unsuccessful: create table v_user_info (id  bigint not null auto_increment, version  bigint not null, name varchar(255) not  null, org_name varchar(255) not null,  primary key (id)) type=InnoDB ERROR hbm2ddl.SchemaExport  ­ Table  v_user_info already exists CONFIDENTIAL 7
    • Database View –> EntityRegister a Custom Configuration in DataSource.groovy dataSource { pooled = true driverClassName = ... username = ... password = ... dialect = ... configClass = gr8conf.DdlFilterConfiguration } CONFIDENTIAL 8
    • Database View –> Entity public class DdlFilterConfiguration extends GrailsAnnotationConfiguration { private static final String[] IGNORED_NAMES = { "v_user_info" }; ... private boolean isIgnored(String command) { command = command.toLowerCase(); for (String table : IGNORED_NAMES) { if (command.startsWith("create table " + table + " ") || command.startsWith("alter table " + table + " ") || command.startsWith("drop table " + table) || command.startsWith("drop table if exists " + table)) { return true; } } return false; } } CONFIDENTIAL 9
    • Database View –> Entity grails-app/conf/hibernate/hibernate.cfg.xml <hibernate­configuration>    <session­factory>       <mapping resource=misc.mysql.innodb.hbm.xml/>       <mapping resource=misc.h2.hbm.xml/>    </session­factory> </hibernate­configuration> CONFIDENTIAL 10
    • Database View –> Entity grails-app/conf/hibernate/misc.mysql.innodb.hbm.xml <hibernate­mapping>    <database­object>       <create>          CREATE OR REPLACE VIEW v_user_info AS          SELECT u.name, u.id, u.version, o.name org_name          FROM auth_user u, organization o          WHERE u.organization_id = o.id       </create>       <drop>DROP VIEW IF EXISTS v_user_info</drop>       <dialect­scope           name=org.hibernate.dialect.MySQLInnoDBDialect />    </database­object> </hibernate­mapping> CONFIDENTIAL 11
    • Subdomain Entity “Subdomain” with a subset of AuthUser data: class Person { String name Organization organization static mapping = { table auth_user } } CONFIDENTIAL 12
    • Subdomain Entity Updatable Subdomain: class Person { String name Organization organization static mapping = { table auth_user dynamicUpdate true } } CONFIDENTIAL 13
    • Writing a Custom Configuration Subclass for Fun and Profit CONFIDENTIAL 14
    • Writing a Custom Configuration Subclass for Fun and ProfitCustom Configurations: http://burtbeckwith.com/blog/?p=465 Examples • Previous SQL generation example • Overrides generateSchemaCreationScript(), generateDropSchemaScript(), and generateSchemaUpdateScript() • Specifying the connection.provider_class property • Overrides buildSettings() • Renaming columns of a composite foreign key • Overrides secondPassCompile() • Overriding the EntityPersister class • Overrides secondPassCompile() • Using field access • Overrides secondPassCompile() CONFIDENTIAL 15
    • Writing a Custom Configuration Subclass for Fun and Profit secondPassCompile() • Access each PersistentClass/RootClass and call any of • addFilter() • setDynamicUpdate() • setBatchSize() • setExplicitPolymorphism() • setCustomSQLDelete() • setOptimisticLockMode() • setCustomSQLInsert() • setSelectBeforeUpdate() • setCustomSQLUpdate() • setWhere() • setDynamicInsert() CONFIDENTIAL 16
    • Read-only Domain Classes CONFIDENTIAL 17
    • Read-only Domain Classes Not 100% possible, but close enough Hibernate • Seems possible via setMutable(false) in a custom Configuration, but: • Wont block saves or deletes, only disables dirty-check updates • Does nothing with collections since theyre a PersistentSet or PersistentList and managed separately (but you wouldnt want to map collections anyway, right?) • See http://docs.jboss.org/hibernate/core/3.5/reference/en/html/readonly.html CONFIDENTIAL 18
    • Read-only Domain Classes Grails • Only beforeUpdate supports vetoing by returning false • A hackish solution would be to throw an exception in beforeDelete and beforeInsert • Better solution: hibernateEventListeners bean in grails­ app/conf/spring/resources.groovy • Still a good idea to use a custom Configuration and call setMutable(false) to reduce memory usage CONFIDENTIAL 19
    • Read-only Domain Classes grails-app/conf/spring/resources.groovy import gr8conf.ReadOnlyEventListener import o.c.g.g.orm.hibernate.HibernateEventListeners beans = {    readOnlyEventListener(ReadOnlyEventListener)    hibernateEventListeners(HibernateEventListeners) {       listenerMap = [pre­delete: readOnlyEventListener,                      pre­insert: readOnlyEventListener,                      pre­update: readOnlyEventListener]    } } CONFIDENTIAL 20
    • Read-only Domain Classes src/groovy/gr8conf/ReadOnlyEventListener.groovy class ReadOnlyEventListener implements PreDeleteEventListener,          PreInsertEventListener, PreUpdateEventListener {  private static final List<String> READ_ONLY = [gr8conf.LegacyData]  boolean onPreDelete(PreDeleteEvent event) {     isReadOnly event.persister.entityName  }  boolean onPreInsert(PreInsertEvent event) {     isReadOnly event.persister.entityName  }  boolean onPreUpdate(PreUpdateEvent event) {     isReadOnly event.persister.entityName  }  private boolean isReadOnly(String name) { READ_ONLY.contains name } } CONFIDENTIAL 21
    • Read-only Domain Classes grails-app/domain/gr8conf/LegacyData.groovy class LegacyData {    String name    static mapping = {       id column: legacy_data_id       version false    } } CONFIDENTIAL 22
    • Read-only Domain Classes ReadOnlyEventListener • delete() • silently fails • Update with save() • silently fails • New instance save() • Throws exception ? CONFIDENTIAL 23
    • Read-only Domain Classes You can also map a second writable domain class to the same table, e.g. for admin: class User { class WritableUser {    String username    String username    String password    String password }    static mapping = {       table user    } } CONFIDENTIAL 24
    • Monitoring CONFIDENTIAL 25
    • Monitoring SQL logging • logSql=true in DataSource.groovy • org.hibernate.SQL → debug, org.hibernate.type → trace appenders {    file name: sql, file: sql.log } debug additivity: false, sql: org.hibernate.SQL trace additivity: false, sql: org.hibernate.type • P6spy plugin • Use SQL Profiler Swing app to view realtime logs; see Mike Hugos blog post Grails, p6spy and Sql Profiler • Run explain (Oracle, MySQL, others) on real queries to look for missing indexes CONFIDENTIAL 26
    • Monitoring Spring Insight lets you drill down to SQL and view timing • http://www.grails.org/screencast/show/13 Profiler plugin can give you timing data JavaMelody Plugin App Info plugin CONFIDENTIAL 27
    • Questions? CONFIDENTIAL 28