From e52b57b7a9f0303c0c710e60870d0ec265d32541 Mon Sep 17 00:00:00 2001
From: Milian Wolff <mail@milianw.de>
Date: Mon, 1 Dec 2014 14:11:19 +0100
Subject: [PATCH 19/30] Optimize queries: Do not retrieve known key used in the
condition.
There is no point in doing a select like:
SELECT foo, bar FROM table WHERE foo = needle;
That can be rewritten to say
SELECT bar FROM table WHERE foo = needle;
This reduces the data traffic with the mysql server. Additionally, it
work-arounds some issues in Qt SQL, which lead to bad performance:
QSqlResult::value incurs multiple temporary allocations, and string
conversions, even to read a simple integer ID for example. Finally,
by reusing an externally provided QString name e.g., we can leverage
Qt's implicit sharing, instead of duplicating the string in a separate
QString instance, with the contents read from SQL server.
REVIEW: 121310
---
server/src/storage/entities.xsl | 50 +++++++++++++++++++++++++++++------------
1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
index 9471293..c8fb1fd 100644
--- a/server/src/storage/entities.xsl
+++ b/server/src/storage/entities.xsl
@@ -104,6 +104,12 @@ Q_DECLARE_TYPEINFO( Akonadi::Server::<xsl:value-of select="@name"/>, Q_MOVABLE_T
using namespace Akonadi::Server;
+static QStringList removeEntry(QStringList list, const QString& entry)
+{
+ list.removeOne(entry);
+ return list;
+}
+
<xsl:for-each select="database/table">
<xsl:call-template name="table-source"/>
</xsl:for-each>
@@ -179,7 +185,8 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
return <xsl:value-of select="$className"/>();
QueryBuilder qb( tableName(), QueryBuilder::Select );
- qb.addColumns( columnNames() );
+ static const QStringList columns = removeEntry(columnNames(), <xsl:value-of select="$key"/>Column());
+ qb.addColumns( columns );
qb.addValueCondition( <xsl:value-of select="$key"/>Column(), Query::Equals, <xsl:value-of select="$key"/> );
if ( !qb.exec() ) {
akDebug() << "Error during selection of record with <xsl:value-of select="$key"/>"
@@ -191,21 +198,36 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
return <xsl:value-of select="$className"/>();
}
+ <!-- this indirection is required to prevent off-by-one access now that we skip the key column -->
+ int valueIndex = 0;
+ <xsl:for-each select="column">
+ const <xsl:value-of select="@type"/> value<xsl:value-of select="position()"/> =
+ <xsl:choose>
+ <xsl:when test="@name=$key">
+ <xsl:value-of select="$key"/>;
+ </xsl:when>
+ <xsl:otherwise>
+ (qb.query().isNull(valueIndex)) ?
+ <xsl:value-of select="@type"/>() :
+ <xsl:choose>
+ <xsl:when test="starts-with(@type,'QString')">
+ Utils::variantToString( qb.query().value( valueIndex ) )
+ </xsl:when>
+ <xsl:when test="starts-with(@type, 'Tristate')">
+ static_cast<Tristate>(qb.query().value( valueIndex ).value<int>())
+ </xsl:when>
+ <xsl:otherwise>
+ qb.query().value( valueIndex ).value<<xsl:value-of select="@type"/>>()
+ </xsl:otherwise>
+ </xsl:choose>
+ ; ++valueIndex;
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
<xsl:value-of select="$className"/> rv(
<xsl:for-each select="column">
- (qb.query().isNull(<xsl:value-of select="position() - 1"/>)) ?
- <xsl:value-of select="@type"/>() :
- <xsl:choose>
- <xsl:when test="starts-with(@type,'QString')">
- Utils::variantToString( qb.query().value( <xsl:value-of select="position() - 1"/> ) )
- </xsl:when>
- <xsl:when test="starts-with(@type, 'Tristate')">
- static_cast<Tristate>(qb.query().value( <xsl:value-of select="position() - 1"/> ).value<int>())
- </xsl:when>
- <xsl:otherwise>
- qb.query().value( <xsl:value-of select="position() - 1"/> ).value<<xsl:value-of select="@type"/>>()
- </xsl:otherwise>
- </xsl:choose>
+ value<xsl:value-of select="position()"/>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
);
--
2.1.0