Permalink
Browse files

Generate MySQL DELETE queries more amenable to optimizations

This MySQL-specific form seems to be subject to more optimizations
than the standard SQL one.
  • Loading branch information...
1 parent 981b1e9 commit 707795f43e24af5a17640a7922cf78de9f436c49 @igstan igstan committed Jul 26, 2016
@@ -464,6 +464,10 @@ trait JdbcStatementBuilderComponent { self: JdbcProfile =>
b.build
}
+ protected def buildDeleteFrom(tableName: String): Unit = {
+ b"delete from $tableName"
+ }
+
def buildDelete: SQLBuilder.Result = {
def fail(msg: String) =
throw new SlickException("Invalid query for DELETE statement: " + msg)
@@ -479,7 +483,7 @@ trait JdbcStatementBuilderComponent { self: JdbcProfile =>
}
val qtn = quoteTableName(from)
symbolName(gen) = qtn // Alias table to itself because DELETE does not support aliases
- b"delete from $qtn"
+ buildDeleteFrom(qtn)
if(!where.isEmpty) {
b" where "
expr(where.reduceLeft((a, b) => Library.And.typed[Boolean](a, b)), true)
@@ -18,6 +18,7 @@ import slick.sql.SqlCapabilities
import slick.util.{SlickLogger, GlobalConfig, ConstArray}
import slick.util.MacroSupport.macroSupportInterpolation
import slick.util.ConfigExtensionMethods.configExtensionMethods
+import slick.util.SQLBuilder.Result
/** Slick profile for MySQL.
*
@@ -182,6 +183,24 @@ trait MySQLProfile extends JdbcProfile { profile =>
expr(n)
if(o.direction.desc) b" desc"
}
+
+ // Override default DELETE FROM syntax in order to produce a more efficient
+ // DELETE query for MySQL.
+ //
+ // Slick cannot directly handle multi-table DELETEs, i.e., using JOIN or
+ // USING, but it can handle subqueries in the WHERE clause of a DELETE.
+ // This is good except for the fact that MySQL doesn't know how to
+ // optimize such semi-join subqueries to joins in single-table DELETE
+ // queries. However, if the DELETE query is a multi-table DELETE, even if
+ // on a single table, then something in MySQL kicks in and optimizes the
+ // subquery to a more efficient JOIN. Further reading:
+ //
+ // - http://mysqlserverteam.com/multi-table-trick
+ // - https://mariadb.com/kb/en/mariadb/semi-join-subquery-optimizations
+ //
+ override protected def buildDeleteFrom(tableName: String): Unit = {
+ b"delete $tableName from $tableName"
+ }
}
class UpsertBuilder(ins: Insert) extends super.UpsertBuilder(ins) {

0 comments on commit 707795f

Please sign in to comment.