diff --git a/src/gxs/rsdataservice.cc b/src/gxs/rsdataservice.cc index 1db2f77c2..022704740 100644 --- a/src/gxs/rsdataservice.cc +++ b/src/gxs/rsdataservice.cc @@ -47,6 +47,11 @@ #define MSG_INDEX_GRPID std::string("INDEX_MESSAGES_GRPID") +// Maximum number of message ids packed into a single "IN (...)" clause. Keeps +// the generated SQL and sqlite's expression tree to a sane size while making +// the per-statement preparation cost negligible. +static const uint32_t MAX_MSG_IDS_PER_QUERY = 500; + // generic #define KEY_NXS_DATA std::string("nxsData") #define KEY_NXS_DATA_LEN std::string("nxsDataLen") @@ -1205,14 +1210,28 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, { RS_STACK_MUTEX(mDbMutex); - // request each grp - for( std::set::const_iterator sit = msgIdV.begin(); - sit!=msgIdV.end();++sit ) - { - const RsGxsMessageId& msgId = *sit; + // Retrieve the requested messages in batches, using a single + // "msgId IN (...)" clause per batch. Preparing one statement per + // message dominates the cost as soon as a request covers more than + // a handful of them (a channel post and its comments, a forum + // thread, a filtered group request). - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, withMeta ? mMsgColumnsWithMeta : mMsgColumns, KEY_GRP_ID+ "='" + grpId.toStdString() - + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); + const std::string selection_prefix = KEY_GRP_ID + "='" + grpId.toStdString() + + "' AND " + KEY_MSG_ID + " IN ("; + + for(auto sit = msgIdV.begin(); sit != msgIdV.end(); ) + { + std::string selection = selection_prefix; + + for(uint32_t i=0; i 0) selection += ","; + selection += "'" + sit->toStdString() + "'"; + } + + selection += ")"; + + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, withMeta ? mMsgColumnsWithMeta : mMsgColumns, selection, ""); ++prof_queries; if(c)