db: Add index on cluster_details.name for FirstFitPlanner speedup (#7922)

This commit is contained in:
Marcus Sorensen 2023-08-31 13:43:23 -06:00 committed by GitHub
parent 439d70fd2b
commit 2cccd8f754
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 1 deletions

View File

@ -18,6 +18,7 @@ package com.cloud.upgrade.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.log4j.Logger;
@ -84,6 +85,33 @@ public class DatabaseAccessObject {
return columnExists;
}
public String generateIndexName(String tableName, String columnName) {
return String.format("i_%s__%s", tableName, columnName);
}
public boolean indexExists(Connection conn, String tableName, String indexName) {
try (PreparedStatement pstmt = conn.prepareStatement(String.format("SHOW INDEXES FROM %s where Key_name = \"%s\"", tableName, indexName))) {
ResultSet result = pstmt.executeQuery();
if (result.next()) {
return true;
}
} catch (SQLException e) {
s_logger.debug(String.format("Index %s doesn't exist, ignoring exception:", indexName, e.getMessage()));
}
return false;
}
public void createIndex(Connection conn, String tableName, String columnName, String indexName) {
String stmt = String.format("CREATE INDEX %s on %s (%s)", indexName, tableName, columnName);
s_logger.debug("Statement: " + stmt);
try (PreparedStatement pstmt = conn.prepareStatement(stmt)) {
pstmt.execute();
s_logger.debug(String.format("Created index %s", indexName));
} catch (SQLException e) {
s_logger.warn(String.format("Unable to create index %s", indexName), e);
}
}
protected static void closePreparedStatement(PreparedStatement pstmt, String errorMessage) {
try {
if (pstmt != null) {
@ -93,5 +121,4 @@ public class DatabaseAccessObject {
s_logger.warn(errorMessage, e);
}
}
}

View File

@ -23,6 +23,14 @@ public class DbUpgradeUtils {
private static DatabaseAccessObject dao = new DatabaseAccessObject();
public static void addIndexIfNeeded(Connection conn, String tableName, String columnName) {
String indexName = dao.generateIndexName(tableName, columnName);
if (!dao.indexExists(conn, tableName, indexName)) {
dao.createIndex(conn, tableName, columnName, indexName);
}
}
public static void addForeignKey(Connection conn, String tableName, String tableColumn, String foreignTableName, String foreignColumnName) {
dao.addForeignKey(conn, tableName, tableColumn, foreignTableName, foreignColumnName);
}

View File

@ -69,6 +69,7 @@ public class Upgrade41800to41810 implements DbUpgrade, DbUpgradeSystemVmTemplate
copyGuestOsMappingsToVMware80u1();
addForeignKeyToAutoscaleVmprofiles(conn);
mergeDuplicateGuestOSes();
addIndexes(conn);
}
private void mergeDuplicateGuestOSes() {
@ -242,4 +243,8 @@ public class Upgrade41800to41810 implements DbUpgrade, DbUpgradeSystemVmTemplate
private void addForeignKeyToAutoscaleVmprofiles(Connection conn) {
DbUpgradeUtils.addForeignKey(conn, "autoscale_vmprofiles", "user_data_id", "user_data", "id");
}
private void addIndexes(Connection conn) {
DbUpgradeUtils.addIndexIfNeeded(conn, "cluster_details", "name");
}
}

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.upgrade.dao;
import static org.mockito.Matchers.startsWith;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.contains;
@ -27,9 +28,11 @@ import static org.mockito.Mockito.when;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -49,6 +52,9 @@ public class DatabaseAccessObjectTest {
@Mock
private Logger loggerMock;
@Mock
private ResultSet resultSetMock;
private final DatabaseAccessObject dao = new DatabaseAccessObject();
@Before
@ -83,6 +89,61 @@ public class DatabaseAccessObjectTest {
dao.dropKey(conn, tableName, key, isForeignKey);
}
@Test
public void generateIndexNameTest() {
String indexName = dao.generateIndexName("mytable","mycolumn");
Assert.assertEquals( "i_mytable__mycolumn", indexName);
}
@Test
public void indexExistsFalseTest() throws Exception {
when(resultSetMock.next()).thenReturn(false);
when(connectionMock.prepareStatement(startsWith("SHOW INDEXES FROM"))).thenReturn(preparedStatementMock);
when(preparedStatementMock.executeQuery()).thenReturn(resultSetMock);
Connection conn = connectionMock;
String tableName = "mytable";
String indexName = "myindex";
Assert.assertFalse(dao.indexExists(conn, tableName, indexName));
verify(connectionMock, times(1)).prepareStatement(anyString());
verify(preparedStatementMock, times(1)).executeQuery();
verify(preparedStatementMock, times(1)).close();
}
@Test
public void indexExistsTrueTest() throws Exception {
when(resultSetMock.next()).thenReturn(true);
when(connectionMock.prepareStatement(startsWith("SHOW INDEXES FROM"))).thenReturn(preparedStatementMock);
when(preparedStatementMock.executeQuery()).thenReturn(resultSetMock);
Connection conn = connectionMock;
String tableName = "mytable";
String indexName = "myindex";
Assert.assertTrue(dao.indexExists(conn, tableName, indexName));
verify(connectionMock, times(1)).prepareStatement(anyString());
verify(preparedStatementMock, times(1)).executeQuery();
verify(preparedStatementMock, times(1)).close();
}
@Test
public void createIndexTest() throws Exception {
when(connectionMock.prepareStatement(startsWith("CREATE INDEX"))).thenReturn(preparedStatementMock);
when(preparedStatementMock.execute()).thenReturn(true);
Connection conn = connectionMock;
String tableName = "mytable";
String columnName = "mycolumn";
String indexName = "myindex";
dao.createIndex(conn, tableName, columnName, indexName);
verify(connectionMock, times(1)).prepareStatement(anyString());
verify(preparedStatementMock, times(1)).execute();
verify(preparedStatementMock, times(1)).close();
verify(loggerMock, times(1)).debug("Created index myindex");
}
@Test
public void testDropKeyWhenTableNameIsNull() throws Exception {
SQLException sqlException = new SQLException();