[Building Sakai] MSGCNTR Forums mysql picks a slow query plan over a faster query plan
Earle Nietzel
earle.nietzel at gmail.com
Fri Sep 2 12:51:50 PDT 2011
Hello everyone,
Got a bit of an issue here with forums and a particular query that mysql is
coming up with different query plans. Depending on which one it selects it
can take a significant amount of time to complete.
The hql in question (added from MSGCNTR-364):
<query
name="findNumModeratedTopicsForSiteByUserByMembershipWithPermissionLevelName">
<![CDATA[select count(*) from
org.sakaiproject.component.app.messageforums.dao.hibernate.TopicImpl as
topic,
org.sakaiproject.component.app.messageforums.dao.hibernate.PermissionLevelImpl
as pl
join topic.openForum as forum
join forum.area as area
join topic.membershipItemSet as membershipItem
where area.contextId = :contextId and
topic.moderated = true and
membershipItem.name in ( :membershipList ) and
pl.moderatePostings = true and
(pl.typeUuid != :customTypeUuid and
pl.name = membershipItem.permissionLevelName)
]]>
</query>
Which then is compiled into this SQL:
select count(*) as col_0_0_
from MFR_TOPIC_T topicimpl0_
inner join MFR_OPEN_FORUM_T openforumi2_ on
topicimpl0_.of_surrogateKey=openforumi2_.ID
inner join MFR_AREA_T areaimpl3_ on openforumi2_.surrogateKey=areaimpl3_.ID
inner join MFR_MEMBERSHIP_ITEM_T membership4_ on
topicimpl0_.ID=membership4_.t_surrogateKey,
MFR_PERMISSION_LEVEL_T permission1_
where areaimpl3_.CONTEXT_ID='517f8f28-f68e-42ee-b168-919a06f82229'
and topicimpl0_.MODERATED=1
and (membership4_.NAME in ('Student' , 'MATH_111L_114_11F'))
and permission1_.MODERATE_POSTINGS=1
and permission1_.TYPE_UUID!='00000000-0000-0000-7777-000000000000'
and permission1_.NAME=membership4_.PERMISSION_LEVEL_NAME
The efficient query plan looks like:
+----+-------------+--------------+------+-------------------------------------------------+------------------------------+---------+-------------------------------------------+-------+--------------------------+
| id | select_type | table | type |
possible_keys |
key | key_len |
ref | rows | Extra
|
+----+-------------+--------------+------+-------------------------------------------------+------------------------------+---------+-------------------------------------------+-------+--------------------------+
| 1 | SIMPLE | areaimpl3_ | ref |
PRIMARY,MFR_AREA_CONTEXT_UUID_UNIQUE,CONTEXT_ID |
MFR_AREA_CONTEXT_UUID_UNIQUE | 767 |
const | 2 | Using where; Using index
|
| 1 | SIMPLE | openforumi2_ | ref |
PRIMARY,FKC17608478B5E2A2F |
FKC17608478B5E2A2F | 9 |
ilearn.areaimpl3_.ID | 3 | Using where; Using index
|
| 1 | SIMPLE | topicimpl0_ | ref |
PRIMARY,FK863DC0BE74C7E92B |
FK863DC0BE74C7E92B | 9 |
ilearn.openforumi2_.ID | 35 | Using where
|
| 1 | SIMPLE | membership4_ | ref |
FKE03761CB7DEF8466,MFRMEMITEM_COMPOSITE_IDX1 |
FKE03761CB7DEF8466 | 9 |
ilearn.topicimpl0_.ID | 3 | Using where
|
| 1 | SIMPLE | permission1_ | ref |
MFRPERMLVL_COMPOSITE_IDX1 |
MFRPERMLVL_COMPOSITE_IDX1 | 152 |
ilearn.membership4_.PERMISSION_LEVEL_NAME | 10167 | Using where
|
+----+-------------+--------------+------+-------------------------------------------------+------------------------------+---------+-------------------------------------------+-------+--------------------------+
The problem occurs when mysql selects a query plan where tables membership4_
and permission1_ are not at the end but towards the top of the query plan
(this query takes several minutes to run):
+----+-------------+--------------+--------+-------------------------------------------------+---------------------------+---------+-------------------------------------------+-------+-------------+
| id | select_type | table | type |
possible_keys | key
| key_len | ref | rows | Extra
|
+----+-------------+--------------+--------+-------------------------------------------------+---------------------------+---------+-------------------------------------------+-------+-------------+
| 1 | SIMPLE | membership4_ | range |
FKE03761CB7DEF8466,MFRMEMITEM_COMPOSITE_IDX1 | MFRMEMITEM_COMPOSITE_IDX1
| 767 |NULL | 67305 | Using where
|
| 1 | SIMPLE | permission1_ | ref |
MFRPERMLVL_NAME_IDX | MFRPERMLVL_NAME_IDX
| 152 | ilearn.membership4_.PERMISSION_LEVEL_NAME | 22004 | Using where
|
| 1 | SIMPLE | topicimpl0_ | eq_ref |
PRIMARY,FK863DC0BE74C7E92B | PRIMARY
| 8 | ilearn.membership4_.t_surrogateKey | 1 | Using where
|
| 1 | SIMPLE | openforumi2_ | eq_ref |
PRIMARY,FKC17608478B5E2A2F | PRIMARY
| 8 | ilearn.topicimpl0_.of_surrogateKey | 1 | Using where
|
| 1 | SIMPLE | areaimpl3_ | eq_ref |
PRIMARY,MFR_AREA_CONTEXT_UUID_UNIQUE,CONTEXT_ID | PRIMARY
| 8 | ilearn.openforumi2_.surrogateKey | 1 | Using where
|
+----+-------------+--------------+--------+-------------------------------------------------+---------------------------+---------+-------------------------------------------+-------+-------------+
At the moment the only way I've been able to make sure mysql doesn't select
the slow query plan is to use straight_join but it appears this is specific
to mysql and therefore not supported by hibernate.
Do we need a to implement a native query specific for MySQL in this case?
Here is some psuedo code to represent what I am thinking:
HibernateCallback hcb = new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException,
SQLException {
if
("mysql".equals(serverConfigurationService.getString(vendor at org.sakaiproject.db.api.SqlService
))
Query q =
session.createSQLQuery(MYSQL_QUERY_GET_NUM_MOD_TOPICS_WITH_MOD_PERM_BY_PERM_LEVEL_NAME);
else
Query q =
session.getNamedQuery(QUERY_GET_NUM_MOD_TOPICS_WITH_MOD_PERM_BY_PERM_LEVEL_NAME);
q.setParameterList("membershipList", membershipList);
q.setParameter("contextId", getContextId(), Hibernate.STRING);
q.setParameter("customTypeUuid", typeManager.getCustomLevelType(),
Hibernate.STRING);
return q.uniqueResult();
}
};
Ideas and thoughts most welcome,
Earle
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://collab.sakaiproject.org/pipermail/sakai-dev/attachments/20110902/3f64990b/attachment.html
More information about the sakai-dev
mailing list