diff --git a/README.md b/README.md index 4c10d54..10aa493 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,10 @@ Supported values for `DatabaseType` parameter are: * `PostgresJsonb` - stores all queryable "logical" columns in a single JSONB column indexed with GIN index of jsonb_path_ops type. Supports only `Equals` and `In` primitive operators. * `SqlServer` -This command has a few database-specific parameters: +There is a parameter specific to the `create` command: +* `DropExisting` - specifies whether to re-create the table if it already exists. + +This command also has a few database-specific parameters: * `ClickHouse.Engine` - table engine. Default is `MergeTree()`. * `ClickHouse.OrderBy` - table sort order. Default is `tuple()`. * `MySql.Engine` - table engine. Default is `InnoDB`. @@ -106,7 +109,7 @@ DatabaseBenchmark query --DatabaseType=MongoDb --ConnectionString="mongodb://loc The same commands can be executed with `--QueryFilePath=SalesAggregateQuery.json` to make sure it works fine with all databases we are going to benchmark. -There are some parameters specific to the query command: +There are some parameters specific to the `query` command: * `BenchmarkName` - benchmark name to be printed in the results table. * `QueryParallelism` - number of parallel threads to be run. * `QueryCount` - number of query executions on each thread. diff --git a/src/DatabaseBenchmark/Commands/CreateCommand.cs b/src/DatabaseBenchmark/Commands/CreateCommand.cs index 36eb884..b8f2e62 100644 --- a/src/DatabaseBenchmark/Commands/CreateCommand.cs +++ b/src/DatabaseBenchmark/Commands/CreateCommand.cs @@ -31,7 +31,7 @@ public void Execute() table.Name = options.TableName; } - database.CreateTable(table); + database.CreateTable(table, options.DropExisting); } } } diff --git a/src/DatabaseBenchmark/Commands/Options/CreateCommandOptions.cs b/src/DatabaseBenchmark/Commands/Options/CreateCommandOptions.cs index 3eacaab..4e462ee 100644 --- a/src/DatabaseBenchmark/Commands/Options/CreateCommandOptions.cs +++ b/src/DatabaseBenchmark/Commands/Options/CreateCommandOptions.cs @@ -19,5 +19,8 @@ public class CreateCommandOptions [Option("Trace queries text and parameters")] public bool TraceQueries { get; set; } = false; + + [Option("Drop table if already exists")] + public bool DropExisting { get; set; } = false; } } diff --git a/src/DatabaseBenchmark/Databases/ClickHouse/ClickHouseDatabase.cs b/src/DatabaseBenchmark/Databases/ClickHouse/ClickHouseDatabase.cs index 69876ab..ce04d3b 100644 --- a/src/DatabaseBenchmark/Databases/ClickHouse/ClickHouseDatabase.cs +++ b/src/DatabaseBenchmark/Databases/ClickHouse/ClickHouseDatabase.cs @@ -29,11 +29,16 @@ public ClickHouseDatabase( _optionsProvider = optionsProvider; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new ClickHouseConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new ClickHouseTableBuilder(_optionsProvider); var commandText = tableBuilder.Build(table); var command = connection.CreateCommand(commandText); diff --git a/src/DatabaseBenchmark/Databases/CosmosDb/CosmosDbDatabase.cs b/src/DatabaseBenchmark/Databases/CosmosDb/CosmosDbDatabase.cs index f74c2e4..b27f984 100644 --- a/src/DatabaseBenchmark/Databases/CosmosDb/CosmosDbDatabase.cs +++ b/src/DatabaseBenchmark/Databases/CosmosDb/CosmosDbDatabase.cs @@ -32,7 +32,7 @@ public CosmosDbDatabase( _optionsProvider = optionsProvider; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { if (table.Columns.Any(c => c.DatabaseGenerated)) { @@ -42,6 +42,18 @@ public void CreateTable(Table table) using var client = new CosmosClient(_connectionString); var database = client.GetDatabase(_databaseName); + if (dropExisting) + { + try + { + var container = database.GetContainer(table.Name); + container.DeleteContainerAsync().Wait(); + } + catch + { + } + } + var partitionKeyName = GetPartitionKeyName(table); database.CreateContainerIfNotExistsAsync(table.Name, "/" + partitionKeyName).Wait(); } diff --git a/src/DatabaseBenchmark/Databases/Elasticsearch/ElasticsearchDatabase.cs b/src/DatabaseBenchmark/Databases/Elasticsearch/ElasticsearchDatabase.cs index 72f2ca2..253ac84 100644 --- a/src/DatabaseBenchmark/Databases/Elasticsearch/ElasticsearchDatabase.cs +++ b/src/DatabaseBenchmark/Databases/Elasticsearch/ElasticsearchDatabase.cs @@ -25,10 +25,21 @@ public ElasticsearchDatabase(string connectionString, IExecutionEnvironment envi _environment = environment; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { + table = NormalizeNames(table); + var client = CreateClient(); + if (dropExisting) + { + var exists = client.Indices.Exists(table.Name); + if (exists.Exists) + { + client.Indices.Delete(table.Name); + } + } + client.Indices.CreateAsync(table.Name, ci => ci .Map(md => md .Properties(pd => BuildProperties(table, pd)))).Wait(); @@ -36,11 +47,13 @@ public void CreateTable(Table table) public ImportResult ImportData(Table table, IDataSource source, int batchSize) { + table = NormalizeNames(table); + if (batchSize <= 0) { batchSize = DefaultImportBatchSize; } - + var client = CreateClient(); var buffer = new List(); @@ -84,7 +97,7 @@ public ImportResult ImportData(Table table, IDataSource source, int batchSize) } public IQueryExecutorFactory CreateQueryExecutorFactory(Table table, Query query) => - new ElasticsearchQueryExecutorFactory(CreateClient, table, query); + new ElasticsearchQueryExecutorFactory(CreateClient, NormalizeNames(table), query); public IQueryExecutorFactory CreateRawQueryExecutorFactory(RawQuery query) => new ElasticsearchRawQueryExecutorFactory(CreateClient, query); @@ -165,5 +178,11 @@ private PropertiesDescriptor BuildProperties(Table table, PropertiesDesc return propertiesDescriptor; } + + private static Table NormalizeNames(Table table) + { + table.Name = table.Name.ToLower(); + return table; + } } } diff --git a/src/DatabaseBenchmark/Databases/Interfaces/IDatabase.cs b/src/DatabaseBenchmark/Databases/Interfaces/IDatabase.cs index d27efbb..2a49e1e 100644 --- a/src/DatabaseBenchmark/Databases/Interfaces/IDatabase.cs +++ b/src/DatabaseBenchmark/Databases/Interfaces/IDatabase.cs @@ -6,7 +6,7 @@ namespace DatabaseBenchmark.Databases.Interfaces { public interface IDatabase { - void CreateTable(Table table); + void CreateTable(Table table, bool dropExisting); ImportResult ImportData(Table table, IDataSource source, int batchSize); diff --git a/src/DatabaseBenchmark/Databases/MonetDb/MonetDbDatabase.cs b/src/DatabaseBenchmark/Databases/MonetDb/MonetDbDatabase.cs index 6b5f70b..fe2215f 100644 --- a/src/DatabaseBenchmark/Databases/MonetDb/MonetDbDatabase.cs +++ b/src/DatabaseBenchmark/Databases/MonetDb/MonetDbDatabase.cs @@ -24,11 +24,16 @@ public MonetDbDatabase(string connectionString, IExecutionEnvironment environmen _environment = environment; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new MonetDbConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new MonetDbTableBuilder(); var commandText = tableBuilder.Build(table); var command = new MonetDbCommand(commandText, connection); diff --git a/src/DatabaseBenchmark/Databases/MongoDb/MongoDbDatabase.cs b/src/DatabaseBenchmark/Databases/MongoDb/MongoDbDatabase.cs index a54049b..a95d34a 100644 --- a/src/DatabaseBenchmark/Databases/MongoDb/MongoDbDatabase.cs +++ b/src/DatabaseBenchmark/Databases/MongoDb/MongoDbDatabase.cs @@ -30,7 +30,7 @@ public MongoDbDatabase( _optionsProvider = optionsProvider; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { //TODO: allow _id field to be marked as database-generated if (table.Columns.Any(c => c.DatabaseGenerated)) @@ -39,6 +39,16 @@ public void CreateTable(Table table) } var database = GetDatabase(); + + if (dropExisting) + { + var collection = database.GetCollection(table.Name); + if (collection != null) + { + database.DropCollection(table.Name); + } + } + database.CreateCollection(table.Name); } diff --git a/src/DatabaseBenchmark/Databases/MySql/MySqlDatabase.cs b/src/DatabaseBenchmark/Databases/MySql/MySqlDatabase.cs index 25abfa4..97bba9c 100644 --- a/src/DatabaseBenchmark/Databases/MySql/MySqlDatabase.cs +++ b/src/DatabaseBenchmark/Databases/MySql/MySqlDatabase.cs @@ -29,11 +29,16 @@ public MySqlDatabase( _optionsProvider = optionsProvider; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new MySqlConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new MySqlTableBuilder(_optionsProvider); var commandText = tableBuilder.Build(table); var command = new MySqlCommand(commandText, connection); diff --git a/src/DatabaseBenchmark/Databases/Oracle/OracleDatabase.cs b/src/DatabaseBenchmark/Databases/Oracle/OracleDatabase.cs index 35b4c72..d30c40f 100644 --- a/src/DatabaseBenchmark/Databases/Oracle/OracleDatabase.cs +++ b/src/DatabaseBenchmark/Databases/Oracle/OracleDatabase.cs @@ -24,11 +24,16 @@ public OracleDatabase(string connectionString, IExecutionEnvironment environment _environment = environment; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new OracleConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new OracleTableBuilder(); var commandText = tableBuilder.Build(table); var command = new OracleCommand(commandText, connection); diff --git a/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlDatabase.cs b/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlDatabase.cs index 92bf8bb..34f7fe0 100644 --- a/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlDatabase.cs +++ b/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlDatabase.cs @@ -23,11 +23,16 @@ public PostgreSqlDatabase(string connectionString, IExecutionEnvironment environ _environment = environment; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new NpgsqlConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new PostgreSqlTableBuilder(); var commandText = tableBuilder.Build(table); var command = new NpgsqlCommand(commandText, connection); diff --git a/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlJsonbDatabase.cs b/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlJsonbDatabase.cs index 207a73c..dde7900 100644 --- a/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlJsonbDatabase.cs +++ b/src/DatabaseBenchmark/Databases/PostgreSql/PostgreSqlJsonbDatabase.cs @@ -24,11 +24,16 @@ public PostgreSqlJsonbDatabase(string connectionString, IExecutionEnvironment en _environment = environment; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new NpgsqlConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new PostgreSqlJsonbTableBuilder(); var commandText = tableBuilder.BuildCreateTableCommandText(table); var command = new NpgsqlCommand(commandText, connection); diff --git a/src/DatabaseBenchmark/Databases/Sql/DbConnectionExtensions.cs b/src/DatabaseBenchmark/Databases/Sql/DbConnectionExtensions.cs new file mode 100644 index 0000000..23d814d --- /dev/null +++ b/src/DatabaseBenchmark/Databases/Sql/DbConnectionExtensions.cs @@ -0,0 +1,20 @@ +using System.Data; + +namespace DatabaseBenchmark.Databases.Sql +{ + public static class DbConnectionExtensions + { + public static void DropTableIfExists(this IDbConnection connection, string tableName) + { + try + { + var dropCommand = connection.CreateCommand(); + dropCommand.CommandText = $"DROP TABLE {tableName}"; + dropCommand.ExecuteNonQuery(); + } + catch + { + } + } + } +} diff --git a/src/DatabaseBenchmark/Databases/SqlServer/SqlServerDatabase.cs b/src/DatabaseBenchmark/Databases/SqlServer/SqlServerDatabase.cs index 51b4e43..69ba97a 100644 --- a/src/DatabaseBenchmark/Databases/SqlServer/SqlServerDatabase.cs +++ b/src/DatabaseBenchmark/Databases/SqlServer/SqlServerDatabase.cs @@ -24,11 +24,16 @@ public SqlServerDatabase(string connectionString, IExecutionEnvironment environm _environment = environment; } - public void CreateTable(Table table) + public void CreateTable(Table table, bool dropExisting) { using var connection = new SqlConnection(_connectionString); connection.Open(); + if (dropExisting) + { + connection.DropTableIfExists(table.Name); + } + var tableBuilder = new SqlServerTableBuilder(); var commandText = tableBuilder.Build(table); var command = new SqlCommand(commandText, connection);