Skip to content

Commit a768745

Browse files
slack-19.0: optimize sqlutils.ToSqlite3Dialect, part 2 (#546)
* Optimize `sqlutils.ToSqlite3Dialect` for inserts Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * gofmt Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * separate index matches Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * skip dml/ddl regex on select Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> * switch block instead Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com> --------- Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
1 parent 32f02b7 commit a768745

File tree

3 files changed

+93
-43
lines changed

3 files changed

+93
-43
lines changed

go/vt/external/golib/sqlutils/sqlite_dialect.go

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,13 @@ var sqlite3GeneralConversions = []regexpMap{
7878
rmap(`(?i)\bconcat[(][\s]*([^,)]+)[\s]*,[\s]*([^,)]+)[\s]*,[\s]*([^,)]+)[\s]*[)]`, `($1 || $2 || $3)`),
7979

8080
rmap(`(?i) rlike `, ` like `),
81+
}
8182

83+
var sqlite3CreateIndexConversions = []regexpMap{
8284
rmap(`(?i)create index([\s\S]+)[(][\s]*[0-9]+[\s]*[)]([\s\S]+)`, `create index ${1}${2}`),
85+
}
86+
87+
var sqlite3DropIndexConversions = []regexpMap{
8388
rmap(`(?i)drop index ([\S]+) on ([\S]+)`, `drop index if exists $1`),
8489
}
8590

@@ -115,20 +120,42 @@ func ToSqlite3CreateTable(statement string) string {
115120
return applyConversions(statement, sqlite3CreateTableConversions)
116121
}
117122

123+
func ToSqlite3CreateIndex(statement string) string {
124+
return applyConversions(statement, sqlite3CreateIndexConversions)
125+
}
126+
127+
func ToSqlite3DropIndex(statement string) string {
128+
return applyConversions(statement, sqlite3DropIndexConversions)
129+
}
130+
118131
func ToSqlite3Insert(statement string) string {
119132
statement = applyConversions(statement, sqlite3GeneralConversions)
120133
return applyConversions(statement, sqlite3InsertConversions)
121134
}
122135

123-
func ToSqlite3Dialect(statement string) (translated string) {
124-
if IsInsert(statement) {
125-
return ToSqlite3Insert(statement)
126-
}
127-
if IsCreateTable(statement) {
128-
return ToSqlite3CreateTable(statement)
129-
}
130-
if IsAlterTable(statement) {
131-
return ToSqlite3CreateTable(statement)
136+
// ToSqlite3Dialect converts a statement to sqlite3 dialect. The statement
137+
// is checked in this order:
138+
// 1. If a query, return the statement with sqlite3GeneralConversions applied.
139+
// 2. If an insert/replace, convert with ToSqlite3Insert.
140+
// 3. If a create index, convert with IsCreateIndex.
141+
// 4. If an drop table, convert with IsDropIndex.
142+
// 5. If a create table, convert with IsCreateTable.
143+
// 6. If an alter table, convert with IsAlterTable.
144+
// 7. As fallback, return the statement with sqlite3GeneralConversions applied.
145+
func ToSqlite3Dialect(statement string, potentiallyDMLOrDDL bool) (translated string) {
146+
if potentiallyDMLOrDDL {
147+
switch {
148+
case IsInsert(statement):
149+
return ToSqlite3Insert(statement)
150+
case IsCreateIndex(statement):
151+
return ToSqlite3CreateIndex(statement)
152+
case IsDropIndex(statement):
153+
return ToSqlite3DropIndex(statement)
154+
case IsCreateTable(statement):
155+
return ToSqlite3CreateTable(statement)
156+
case IsAlterTable(statement):
157+
return ToSqlite3CreateTable(statement)
158+
}
132159
}
133160
return applyConversions(statement, sqlite3GeneralConversions)
134161
}

go/vt/external/golib/sqlutils/sqlite_dialect_test.go

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package sqlutils
2222

2323
import (
24+
"fmt"
2425
"regexp"
2526
"strings"
2627
"testing"
@@ -91,7 +92,7 @@ func TestToSqlite3AlterTable(t *testing.T) {
9192
database_instance
9293
ADD COLUMN sql_delay INT UNSIGNED NOT NULL AFTER replica_lag_seconds
9394
`
94-
result := stripSpaces(ToSqlite3Dialect(statement))
95+
result := stripSpaces(ToSqlite3Dialect(statement, true))
9596
require.Equal(t, result, stripSpaces(`
9697
ALTER TABLE
9798
database_instance
@@ -104,7 +105,7 @@ func TestToSqlite3AlterTable(t *testing.T) {
104105
database_instance
105106
ADD INDEX source_host_port_idx (source_host, source_port)
106107
`
107-
result := stripSpaces(ToSqlite3Dialect(statement))
108+
result := stripSpaces(ToSqlite3Dialect(statement, true))
108109
require.Equal(t, result, stripSpaces(`
109110
create index
110111
source_host_port_idx_database_instance
@@ -117,7 +118,7 @@ func TestToSqlite3AlterTable(t *testing.T) {
117118
topology_recovery
118119
ADD KEY last_detection_idx (last_detection_id)
119120
`
120-
result := stripSpaces(ToSqlite3Dialect(statement))
121+
result := stripSpaces(ToSqlite3Dialect(statement, true))
121122
require.Equal(t, result, stripSpaces(`
122123
create index
123124
last_detection_idx_topology_recovery
@@ -134,7 +135,7 @@ func TestCreateIndex(t *testing.T) {
134135
source_host_port_idx_database_instance
135136
on database_instance (source_host(128), source_port)
136137
`
137-
result := stripSpaces(ToSqlite3Dialect(statement))
138+
result := stripSpaces(ToSqlite3Dialect(statement, true))
138139
require.Equal(t, result, stripSpaces(`
139140
create index
140141
source_host_port_idx_database_instance
@@ -173,7 +174,7 @@ func TestToSqlite3Insert(t *testing.T) {
173174
domain_name=values(domain_name),
174175
last_registered=values(last_registered)
175176
`
176-
result := stripSpaces(ToSqlite3Dialect(statement))
177+
result := stripSpaces(ToSqlite3Dialect(statement, true))
177178
require.Equal(t, result, stripSpaces(`
178179
replace into
179180
cluster_domain_name (cluster_name, domain_name, last_registered)
@@ -186,62 +187,62 @@ func TestToSqlite3Insert(t *testing.T) {
186187
func TestToSqlite3GeneralConversions(t *testing.T) {
187188
{
188189
statement := "select now()"
189-
result := ToSqlite3Dialect(statement)
190+
result := ToSqlite3Dialect(statement, false)
190191
require.Equal(t, result, "select datetime('now')")
191192
}
192193
{
193194
statement := "select now() - interval ? second"
194-
result := ToSqlite3Dialect(statement)
195+
result := ToSqlite3Dialect(statement, false)
195196
require.Equal(t, result, "select datetime('now', printf('-%d second', ?))")
196197
}
197198
{
198199
statement := "select now() + interval ? minute"
199-
result := ToSqlite3Dialect(statement)
200+
result := ToSqlite3Dialect(statement, false)
200201
require.Equal(t, result, "select datetime('now', printf('+%d minute', ?))")
201202
}
202203
{
203204
statement := "select now() + interval 5 minute"
204-
result := ToSqlite3Dialect(statement)
205+
result := ToSqlite3Dialect(statement, false)
205206
require.Equal(t, result, "select datetime('now', '+5 minute')")
206207
}
207208
{
208209
statement := "select some_table.some_column + interval ? minute"
209-
result := ToSqlite3Dialect(statement)
210+
result := ToSqlite3Dialect(statement, false)
210211
require.Equal(t, result, "select datetime(some_table.some_column, printf('+%d minute', ?))")
211212
}
212213
{
213214
statement := "AND primary_instance.last_attempted_check <= primary_instance.last_seen + interval ? minute"
214-
result := ToSqlite3Dialect(statement)
215+
result := ToSqlite3Dialect(statement, false)
215216
require.Equal(t, result, "AND primary_instance.last_attempted_check <= datetime(primary_instance.last_seen, printf('+%d minute', ?))")
216217
}
217218
{
218219
statement := "select concat(primary_instance.port, '') as port"
219-
result := ToSqlite3Dialect(statement)
220+
result := ToSqlite3Dialect(statement, false)
220221
require.Equal(t, result, "select (primary_instance.port || '') as port")
221222
}
222223
{
223224
statement := "select concat( 'abc' , 'def') as s"
224-
result := ToSqlite3Dialect(statement)
225+
result := ToSqlite3Dialect(statement, false)
225226
require.Equal(t, result, "select ('abc' || 'def') as s")
226227
}
227228
{
228229
statement := "select concat( 'abc' , 'def', last.col) as s"
229-
result := ToSqlite3Dialect(statement)
230+
result := ToSqlite3Dialect(statement, false)
230231
require.Equal(t, result, "select ('abc' || 'def' || last.col) as s")
231232
}
232233
{
233234
statement := "select concat(myself.only) as s"
234-
result := ToSqlite3Dialect(statement)
235+
result := ToSqlite3Dialect(statement, false)
235236
require.Equal(t, result, "select concat(myself.only) as s")
236237
}
237238
{
238239
statement := "select concat(1, '2', 3, '4') as s"
239-
result := ToSqlite3Dialect(statement)
240+
result := ToSqlite3Dialect(statement, false)
240241
require.Equal(t, result, "select concat(1, '2', 3, '4') as s")
241242
}
242243
{
243244
statement := "select group_concat( 'abc' , 'def') as s"
244-
result := ToSqlite3Dialect(statement)
245+
result := ToSqlite3Dialect(statement, false)
245246
require.Equal(t, result, "select group_concat( 'abc' , 'def') as s")
246247
}
247248
}
@@ -307,27 +308,45 @@ func TestToSqlite3Dialect(t *testing.T) {
307308

308309
for _, test := range tests {
309310
t.Run(test.input, func(t *testing.T) {
310-
result := ToSqlite3Dialect(test.input)
311+
result := ToSqlite3Dialect(test.input, true)
311312
assert.Equal(t, test.expected, result)
312313
})
313314
}
314315
}
315316

316-
func BenchmarkToSqlite3Dialect_Insert(b *testing.B) {
317-
statement := `INSERT ignore INTO database_instance
318-
(alias, hostname, port, last_checked, last_attempted_check, last_check_partial_success, server_id, server_uuid,
319-
version, major_version, version_comment, binlog_server, read_only, binlog_format,
320-
binlog_row_image, log_bin, log_replica_updates, binary_log_file, binary_log_pos, source_host, source_port, replica_net_timeout, heartbeat_interval,
321-
replica_sql_running, replica_io_running, replication_sql_thread_state, replication_io_thread_state, has_replication_filters, supports_oracle_gtid, oracle_gtid, source_uuid, ancestry_uuid, executed_gtid_set, gtid_mode, gtid_purged, gtid_errant, mariadb_gtid, pseudo_gtid,
322-
source_log_file, read_source_log_pos, relay_source_log_file, exec_source_log_pos, relay_log_file, relay_log_pos, last_sql_error, last_io_error, replication_lag_seconds, replica_lag_seconds, sql_delay, data_center, region, physical_environment, replication_depth, is_co_primary, has_replication_credentials, allow_tls, semi_sync_enforced, semi_sync_primary_enabled, semi_sync_primary_timeout, semi_sync_primary_wait_for_replica_count, semi_sync_replica_enabled, semi_sync_primary_status, semi_sync_primary_clients, semi_sync_replica_status, last_discovery_latency, last_seen)
317+
func buildToSqlite3Dialect_Insert(instances int) string {
318+
var rows []string
319+
for i := 0; i < instances; i++ {
320+
rows = append(rows, `(?, ?, ?, NOW(), NOW(), 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`)
321+
}
322+
323+
return fmt.Sprintf(`INSERT ignore INTO database_instance
324+
(alias, hostname, port, last_checked, last_attempted_check, last_check_partial_success, server_id, server_uuid,
325+
version, major_version, version_comment, binlog_server, read_only, binlog_format,
326+
binlog_row_image, log_bin, log_replica_updates, binary_log_file, binary_log_pos, source_host, source_port, replica_net_timeout, heartbeat_interval,
327+
replica_sql_running, replica_io_running, replication_sql_thread_state, replication_io_thread_state, has_replication_filters, supports_oracle_gtid, oracle_gtid, source_uuid, ancestry_uuid, executed_gtid_set, gtid_mode, gtid_purged, gtid_errant, mariadb_gtid, pseudo_gtid,
328+
source_log_file, read_source_log_pos, relay_source_log_file, exec_source_log_pos, relay_log_file, relay_log_pos, last_sql_error, last_io_error, replication_lag_seconds, replica_lag_seconds, sql_delay, data_center, region, physical_environment, replication_depth, is_co_primary, has_replication_credentials, allow_tls, semi_sync_enforced, semi_sync_primary_enabled, semi_sync_primary_timeout, semi_sync_primary_wait_for_replica_count, semi_sync_replica_enabled, semi_sync_primary_status, semi_sync_primary_clients, semi_sync_replica_status, last_discovery_latency, last_seen)
323329
VALUES
324-
(?, ?, ?, NOW(), NOW(), 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
330+
%s
325331
ON DUPLICATE KEY UPDATE
326-
alias=VALUES(alias), hostname=VALUES(hostname), port=VALUES(port), last_checked=VALUES(last_checked), last_attempted_check=VALUES(last_attempted_check), last_check_partial_success=VALUES(last_check_partial_success), server_id=VALUES(server_id), server_uuid=VALUES(server_uuid), version=VALUES(version), major_version=VALUES(major_version), version_comment=VALUES(version_comment), binlog_server=VALUES(binlog_server), read_only=VALUES(read_only), binlog_format=VALUES(binlog_format), binlog_row_image=VALUES(binlog_row_image), log_bin=VALUES(log_bin), log_replica_updates=VALUES(log_replica_updates), binary_log_file=VALUES(binary_log_file), binary_log_pos=VALUES(binary_log_pos), source_host=VALUES(source_host), source_port=VALUES(source_port), replica_net_timeout=VALUES(replica_net_timeout), heartbeat_interval=VALUES(heartbeat_interval), replica_sql_running=VALUES(replica_sql_running), replica_io_running=VALUES(replica_io_running), replication_sql_thread_state=VALUES(replication_sql_thread_state), replication_io_thread_state=VALUES(replication_io_thread_state), has_replication_filters=VALUES(has_replication_filters), supports_oracle_gtid=VALUES(supports_oracle_gtid), oracle_gtid=VALUES(oracle_gtid), source_uuid=VALUES(source_uuid), ancestry_uuid=VALUES(ancestry_uuid), executed_gtid_set=VALUES(executed_gtid_set), gtid_mode=VALUES(gtid_mode), gtid_purged=VALUES(gtid_purged), gtid_errant=VALUES(gtid_errant), mariadb_gtid=VALUES(mariadb_gtid), pseudo_gtid=VALUES(pseudo_gtid), source_log_file=VALUES(source_log_file), read_source_log_pos=VALUES(read_source_log_pos), relay_source_log_file=VALUES(relay_source_log_file), exec_source_log_pos=VALUES(exec_source_log_pos), relay_log_file=VALUES(relay_log_file), relay_log_pos=VALUES(relay_log_pos), last_sql_error=VALUES(last_sql_error), last_io_error=VALUES(last_io_error), replication_lag_seconds=VALUES(replication_lag_seconds), replica_lag_seconds=VALUES(replica_lag_seconds), sql_delay=VALUES(sql_delay), data_center=VALUES(data_center), region=VALUES(region), physical_environment=VALUES(physical_environment), replication_depth=VALUES(replication_depth), is_co_primary=VALUES(is_co_primary), has_replication_credentials=VALUES(has_replication_credentials), allow_tls=VALUES(allow_tls),
327-
semi_sync_enforced=VALUES(semi_sync_enforced), semi_sync_primary_enabled=VALUES(semi_sync_primary_enabled), semi_sync_primary_timeout=VALUES(semi_sync_primary_timeout), semi_sync_primary_wait_for_replica_count=VALUES(semi_sync_primary_wait_for_replica_count), semi_sync_replica_enabled=VALUES(semi_sync_replica_enabled), semi_sync_primary_status=VALUES(semi_sync_primary_status), semi_sync_primary_clients=VALUES(semi_sync_primary_clients), semi_sync_replica_status=VALUES(semi_sync_replica_status),
328-
last_discovery_latency=VALUES(last_discovery_latency), last_seen=VALUES(last_seen)
329-
`
332+
alias=VALUES(alias), hostname=VALUES(hostname), port=VALUES(port), last_checked=VALUES(last_checked), last_attempted_check=VALUES(last_attempted_check), last_check_partial_success=VALUES(last_check_partial_success), server_id=VALUES(server_id), server_uuid=VALUES(server_uuid), version=VALUES(version), major_version=VALUES(major_version), version_comment=VALUES(version_comment), binlog_server=VALUES(binlog_server), read_only=VALUES(read_only), binlog_format=VALUES(binlog_format), binlog_row_image=VALUES(binlog_row_image), log_bin=VALUES(log_bin), log_replica_updates=VALUES(log_replica_updates), binary_log_file=VALUES(binary_log_file), binary_log_pos=VALUES(binary_log_pos), source_host=VALUES(source_host), source_port=VALUES(source_port), replica_net_timeout=VALUES(replica_net_timeout), heartbeat_interval=VALUES(heartbeat_interval), replica_sql_running=VALUES(replica_sql_running), replica_io_running=VALUES(replica_io_running), replication_sql_thread_state=VALUES(replication_sql_thread_state), replication_io_thread_state=VALUES(replication_io_thread_state), has_replication_filters=VALUES(has_replication_filters), supports_oracle_gtid=VALUES(supports_oracle_gtid), oracle_gtid=VALUES(oracle_gtid), source_uuid=VALUES(source_uuid), ancestry_uuid=VALUES(ancestry_uuid), executed_gtid_set=VALUES(executed_gtid_set), gtid_mode=VALUES(gtid_mode), gtid_purged=VALUES(gtid_purged), gtid_errant=VALUES(gtid_errant), mariadb_gtid=VALUES(mariadb_gtid), pseudo_gtid=VALUES(pseudo_gtid), source_log_file=VALUES(source_log_file), read_source_log_pos=VALUES(read_source_log_pos), relay_source_log_file=VALUES(relay_source_log_file), exec_source_log_pos=VALUES(exec_source_log_pos), relay_log_file=VALUES(relay_log_file), relay_log_pos=VALUES(relay_log_pos), last_sql_error=VALUES(last_sql_error), last_io_error=VALUES(last_io_error), replication_lag_seconds=VALUES(replication_lag_seconds), replica_lag_seconds=VALUES(replica_lag_seconds), sql_delay=VALUES(sql_delay), data_center=VALUES(data_center), region=VALUES(region), physical_environment=VALUES(physical_environment), replication_depth=VALUES(replication_depth), is_co_primary=VALUES(is_co_primary), has_replication_credentials=VALUES(has_replication_credentials), allow_tls=VALUES(allow_tls),
333+
semi_sync_enforced=VALUES(semi_sync_enforced), semi_sync_primary_enabled=VALUES(semi_sync_primary_enabled), semi_sync_primary_timeout=VALUES(semi_sync_primary_timeout), semi_sync_primary_wait_for_replica_count=VALUES(semi_sync_primary_wait_for_replica_count), semi_sync_replica_enabled=VALUES(semi_sync_replica_enabled), semi_sync_primary_status=VALUES(semi_sync_primary_status), semi_sync_primary_clients=VALUES(semi_sync_primary_clients), semi_sync_replica_status=VALUES(semi_sync_replica_status),
334+
last_discovery_latency=VALUES(last_discovery_latency), last_seen=VALUES(last_seen)
335+
`, strings.Join(rows, "\n\t\t\t\t"))
336+
}
337+
338+
func BenchmarkToSqlite3Dialect_Insert1000(b *testing.B) {
330339
for i := 0; i < b.N; i++ {
331-
ToSqlite3Dialect(statement)
340+
b.StopTimer()
341+
statement := buildToSqlite3Dialect_Insert(1000)
342+
b.StartTimer()
343+
ToSqlite3Dialect(statement, true)
344+
}
345+
}
346+
347+
func BenchmarkToSqlite3Dialect_Select(b *testing.B) {
348+
for i := 0; i < b.N; i++ {
349+
statement := "select now() - interval ? second"
350+
ToSqlite3Dialect(statement, false)
332351
}
333352
}

go/vt/vtorc/db/db.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ func OpenVTOrc() (db *sql.DB, err error) {
6969
}
7070

7171
func translateStatement(statement string) string {
72-
return sqlutils.ToSqlite3Dialect(statement)
72+
return sqlutils.ToSqlite3Dialect(statement, true /* potentiallyDMLOrDDL */)
73+
}
74+
75+
func translateQueryStatement(statement string) string {
76+
return sqlutils.ToSqlite3Dialect(statement, false /* potentiallyDMLOrDDL */)
7377
}
7478

7579
// registerVTOrcDeployment updates the vtorc_db_deployments table upon successful deployment
@@ -162,7 +166,7 @@ func ExecVTOrc(query string, args ...any) (sql.Result, error) {
162166

163167
// QueryVTOrcRowsMap
164168
func QueryVTOrcRowsMap(query string, onRow func(sqlutils.RowMap) error) error {
165-
query = translateStatement(query)
169+
query = translateQueryStatement(query)
166170
db, err := OpenVTOrc()
167171
if err != nil {
168172
return err
@@ -173,7 +177,7 @@ func QueryVTOrcRowsMap(query string, onRow func(sqlutils.RowMap) error) error {
173177

174178
// QueryVTOrc
175179
func QueryVTOrc(query string, argsArray []any, onRow func(sqlutils.RowMap) error) error {
176-
query = translateStatement(query)
180+
query = translateQueryStatement(query)
177181
db, err := OpenVTOrc()
178182
if err != nil {
179183
return err

0 commit comments

Comments
 (0)