forked from github-mirror/CoreProtect
Improved MySQL index handling (fixes #867)
This commit is contained in:
1 parent
ff36b6e0e6
commit
d69fffbce0
2 files changed
+108
-9
No files matched your search
@@ -12,6 +12,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -326,6 +327,7 @@ public class Database extends Queue {
|
|||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
Statement statement = connection.createStatement();
|
Statement statement = connection.createStatement();
|
||||||
createMySQLTableStructures(prefix, statement);
|
createMySQLTableStructures(prefix, statement);
|
||||||
|
createMySQLIndexes(prefix, statement, purge);
|
||||||
if (!purge && forceConnection == null) {
|
if (!purge && forceConnection == null) {
|
||||||
initializeTables(prefix, statement);
|
initializeTables(prefix, statement);
|
||||||
}
|
}
|
||||||
@@ -413,6 +415,103 @@ public class Database extends Queue {
|
|||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,world varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
|
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,world varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void createMySQLIndexes(String prefix, Statement statement, boolean purge) {
|
||||||
|
try {
|
||||||
|
ensureMySQLIndex(statement, prefix + "block", "wid", "x", "z", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "block", "user", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "block", "type", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "container", "wid", "x", "z", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "container", "user", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "container", "type", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "item", "wid", "x", "z", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "item", "user", "time");
|
||||||
|
ensureMySQLIndex(statement, prefix + "item", "type", "time");
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Chat.console(Phrase.build(Phrase.DATABASE_INDEX_ERROR));
|
||||||
|
if (purge) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureMySQLIndex(Statement statement, String tableName, String... columns) throws SQLException {
|
||||||
|
if (hasMySQLIndex(statement, tableName, columns)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String indexName = createMySQLIndexName(tableName, columns);
|
||||||
|
String indexColumns = String.join(",", columns);
|
||||||
|
statement.executeUpdate("CREATE INDEX " + indexName + " ON " + tableName + "(" + indexColumns + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasMySQLIndex(Statement statement, String tableName, String... columns) {
|
||||||
|
Map<String, TreeMap<Integer, String>> indexData = new HashMap<>();
|
||||||
|
|
||||||
|
try (ResultSet resultSet = statement.executeQuery("SHOW INDEX FROM " + tableName)) {
|
||||||
|
while (resultSet.next()) {
|
||||||
|
String keyName = resultSet.getString("Key_name");
|
||||||
|
int sequence = resultSet.getInt("Seq_in_index");
|
||||||
|
String columnName = resultSet.getString("Column_name");
|
||||||
|
if (keyName == null || columnName == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexData.computeIfAbsent(keyName, key -> new TreeMap<>()).put(sequence, columnName.toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> expected = new ArrayList<>(columns.length);
|
||||||
|
for (String column : columns) {
|
||||||
|
expected.add(column.toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TreeMap<Integer, String> indexColumns : indexData.values()) {
|
||||||
|
if (indexColumns.size() < expected.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matchesPrefix = true;
|
||||||
|
int position = 0;
|
||||||
|
for (String column : indexColumns.values()) {
|
||||||
|
if (!column.equals(expected.get(position))) {
|
||||||
|
matchesPrefix = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
position++;
|
||||||
|
if (position == expected.size()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchesPrefix && position == expected.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createMySQLIndexName(String tableName, String... columns) {
|
||||||
|
String normalizedTable = tableName.replaceAll("[^A-Za-z0-9_]", "_");
|
||||||
|
String joinedColumns = String.join("_", columns);
|
||||||
|
String candidate = normalizedTable + "_" + joinedColumns + "_idx";
|
||||||
|
if (candidate.length() <= 64) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
String hash = Integer.toHexString(candidate.hashCode());
|
||||||
|
int maxPrefixLength = 64 - (hash.length() + 1);
|
||||||
|
if (maxPrefixLength < 1) {
|
||||||
|
maxPrefixLength = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidate.substring(0, maxPrefixLength) + "_" + hash;
|
||||||
|
}
|
||||||
|
|
||||||
private static void createSQLiteTables(String prefix, boolean forcePrefix, Connection forceConnection, boolean purge) {
|
private static void createSQLiteTables(String prefix, boolean forcePrefix, Connection forceConnection, boolean purge) {
|
||||||
try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, 0))) {
|
try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, 0))) {
|
||||||
Statement statement = connection.createStatement();
|
Statement statement = connection.createStatement();
|
||||||
|
|||||||
@@ -586,17 +586,17 @@ public class LookupRaw extends Queue {
|
|||||||
String unionSelect = "SELECT * FROM (";
|
String unionSelect = "SELECT * FROM (";
|
||||||
if (Config.getGlobal().MYSQL) {
|
if (Config.getGlobal().MYSQL) {
|
||||||
if (queryTable.equals("block")) {
|
if (queryTable.equals("block")) {
|
||||||
if (includeBlock.length() > 0 || includeEntity.length() > 0) {
|
|
||||||
index = "USE INDEX(type) IGNORE INDEX(user,wid) ";
|
|
||||||
}
|
|
||||||
if (users.length() > 0) {
|
|
||||||
index = "USE INDEX(user) IGNORE INDEX(type,wid) ";
|
|
||||||
}
|
|
||||||
if (radius != null && (radius[2] - radius[1]) <= 50 && (radius[6] - radius[5]) <= 50) {
|
if (radius != null && (radius[2] - radius[1]) <= 50 && (radius[6] - radius[5]) <= 50) {
|
||||||
index = "USE INDEX(wid) IGNORE INDEX(type,user) ";
|
index = "USE INDEX(wid) ";
|
||||||
}
|
}
|
||||||
if ((restrictWorld && (users.length() > 0 || includeBlock.length() > 0 || includeEntity.length() > 0))) {
|
else if (users.length() > 0) {
|
||||||
index = "IGNORE INDEX(PRIMARY) ";
|
index = "USE INDEX(user) ";
|
||||||
|
}
|
||||||
|
else if (includeBlock.length() > 0 || includeEntity.length() > 0) {
|
||||||
|
index = "USE INDEX(type) ";
|
||||||
|
}
|
||||||
|
else if (restrictWorld) {
|
||||||
|
index = "USE INDEX(wid) ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user