From 3391e3d34b10fe157c020fe6fa10c492257c98e6 Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Fri, 5 Apr 2013 23:02:06 -0700 Subject: [PATCH] Use (a = ? AND b = ?) instead of (a, b) IN (?, ?) Summary: MySQL is not able to use indexes with searching for tuples. Test Plan: Explained the query before and after, saw `key_len` 16 instead of 8. Also saw time 0.0 s instead of 2.9 s (but that was probably caused by warming up). Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D5580 --- .../diffusion/query/browse/DiffusionSvnBrowseQuery.php | 8 +++++--- src/docs/developer/database.diviner | 4 ++++ .../daemon/workers/query/PhabricatorWorkerLeaseQuery.php | 6 +++--- src/infrastructure/edges/editor/PhabricatorEdgeEditor.php | 6 +++--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/applications/diffusion/query/browse/DiffusionSvnBrowseQuery.php b/src/applications/diffusion/query/browse/DiffusionSvnBrowseQuery.php index 4e1467e6f7..074aaf92d0 100644 --- a/src/applications/diffusion/query/browse/DiffusionSvnBrowseQuery.php +++ b/src/applications/diffusion/query/browse/DiffusionSvnBrowseQuery.php @@ -102,7 +102,9 @@ final class DiffusionSvnBrowseQuery extends DiffusionBrowseQuery { $sql = array(); foreach ($index as $row) { - $sql[] = '('.(int)$row['pathID'].', '.(int)$row['maxCommit'].')'; + $sql[] = + '(pathID = '.(int)$row['pathID'].' AND '. + 'svnCommit = '.(int)$row['maxCommit'].')'; } $browse = queryfx_all( @@ -112,13 +114,13 @@ final class DiffusionSvnBrowseQuery extends DiffusionBrowseQuery { WHERE repositoryID = %d AND parentID = %d AND existed = 1 - AND (pathID, svnCommit) in (%Q) + AND (%Q) ORDER BY pathName', PhabricatorRepository::TABLE_FILESYSTEM, PhabricatorRepository::TABLE_PATH, $repository->getID(), $path_id, - implode(', ', $sql)); + implode(' OR ', $sql)); $loadable_commits = array(); foreach ($browse as $key => $file) { diff --git a/src/docs/developer/database.diviner b/src/docs/developer/database.diviner index 8ad4e349f3..6b085039cc 100644 --- a/src/docs/developer/database.diviner +++ b/src/docs/developer/database.diviner @@ -96,6 +96,10 @@ Create all indexes necessary for fast query execution in most cases. Don't create indexes which are not used. You can analyze queries @{article:Using DarkConsole}. +Older MySQL versions are not able to use indexes for tuple search: +`(a, b) IN ((%s, %d), (%s, %d))`. Use `AND` and `OR` instead: +`((a = %s AND b = %d) OR (a = %s AND b = %d))`. + = Foreign Keys = We don't use InnoDB's foreign keys because our application is so great that diff --git a/src/infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php b/src/infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php index d4996e3e35..e54fb72d3e 100644 --- a/src/infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php +++ b/src/infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php @@ -171,14 +171,14 @@ final class PhabricatorWorkerLeaseQuery extends PhabricatorQuery { foreach ($rows as $row) { $in[] = qsprintf( $conn_w, - '(%d, %s)', + '(id = %d AND leaseOwner = %s)', $row['id'], $row['leaseOwner']); } $where[] = qsprintf( $conn_w, - '(id, leaseOwner) IN (%Q)', - '('.implode(', ', $in).')'); + '(%Q)', + implode(' OR ', $in)); break; default: throw new Exception("Unknown phase '{$phase}'!"); diff --git a/src/infrastructure/edges/editor/PhabricatorEdgeEditor.php b/src/infrastructure/edges/editor/PhabricatorEdgeEditor.php index edda35cf0f..4ee2b68b84 100644 --- a/src/infrastructure/edges/editor/PhabricatorEdgeEditor.php +++ b/src/infrastructure/edges/editor/PhabricatorEdgeEditor.php @@ -306,7 +306,7 @@ final class PhabricatorEdgeEditor extends PhabricatorEditor { foreach ($edges as $edge) { $sql[] = qsprintf( $conn_w, - '(%s, %d, %s)', + '(src = %s AND type = %d AND dst = %s)', $edge['src'], $edge['type'], $edge['dst']); @@ -323,9 +323,9 @@ final class PhabricatorEdgeEditor extends PhabricatorEditor { foreach (array_chunk($sql, 256) as $chunk) { queryfx( $conn_w, - 'DELETE FROM %T WHERE (src, type, dst) IN (%Q)', + 'DELETE FROM %T WHERE (%Q)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, - implode(', ', $chunk)); + implode(' OR ', $chunk)); } } }