mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-18 22:44:10 +02:00
Much, much faster extract() implementation, refs #172
Takes my test down from ten minutes to four seconds.
This commit is contained in:
parent
0ca5585fcb
commit
61015c8f64
1 changed files with 50 additions and 26 deletions
|
|
@ -886,38 +886,62 @@ class Table(Queryable):
|
||||||
first_column = columns[0]
|
first_column = columns[0]
|
||||||
pks = self.pks
|
pks = self.pks
|
||||||
lookup_table = self.db[table]
|
lookup_table = self.db[table]
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=128)
|
|
||||||
def cached_lookup(lookups):
|
|
||||||
return lookup_table.lookup(dict(lookups))
|
|
||||||
|
|
||||||
if pks == ["rowid"]:
|
|
||||||
rows_iter = self.rows_where(select="rowid, *")
|
|
||||||
else:
|
|
||||||
rows_iter = self.rows
|
|
||||||
for row in rows_iter:
|
|
||||||
row_pks = tuple(row[pk] for pk in pks)
|
|
||||||
lookups = tuple(
|
|
||||||
(rename.get(column) or column, row[column]) for column in columns
|
|
||||||
)
|
|
||||||
self.update(
|
|
||||||
row_pks,
|
|
||||||
{first_column: cached_lookup(lookups)},
|
|
||||||
assume_exists=True,
|
|
||||||
pks=self.pks,
|
|
||||||
)
|
|
||||||
if progress:
|
|
||||||
progress(1)
|
|
||||||
fk_column = fk_column or "{}_id".format(table)
|
fk_column = fk_column or "{}_id".format(table)
|
||||||
# Now rename first_column and change its type to integer, and drop
|
magic_lookup_column = "{}_{}".format(fk_column, os.urandom(6).hex())
|
||||||
# any other extracted columns:
|
|
||||||
self.transform(
|
# Populate the lookup table with all of the extracted unique values
|
||||||
types={first_column: int},
|
lookup_cols = {
|
||||||
drop=set(columns[1:]),
|
(rename.get(col) or col): typ
|
||||||
rename={first_column: fk_column},
|
for col, typ in self.columns_dict.items()
|
||||||
|
if col in columns
|
||||||
|
}
|
||||||
|
lookup_table.create(
|
||||||
|
{
|
||||||
|
**{
|
||||||
|
"id": int,
|
||||||
|
},
|
||||||
|
**lookup_cols,
|
||||||
|
},
|
||||||
|
pk="id",
|
||||||
)
|
)
|
||||||
|
lookup_columns = [(rename.get(col) or col) for col in columns]
|
||||||
|
lookup_table.create_index(lookup_columns, unique=True)
|
||||||
|
self.db.execute(
|
||||||
|
"INSERT INTO [{lookup_table}] ({lookup_columns}) SELECT DISTINCT {table_cols} FROM [{table}]".format(
|
||||||
|
lookup_table=table,
|
||||||
|
lookup_columns=", ".join("[{}]".format(c) for c in lookup_columns),
|
||||||
|
table_cols=", ".join("[{}]".format(c) for c in columns),
|
||||||
|
table=self.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now add the new fk_column
|
||||||
|
self.add_column(magic_lookup_column, int)
|
||||||
|
|
||||||
|
# And populate it
|
||||||
|
self.db.execute(
|
||||||
|
"UPDATE [{table}] SET [{magic_lookup_column}] = (SELECT id FROM [{lookup_table}] WHERE {where})".format(
|
||||||
|
table=self.name,
|
||||||
|
magic_lookup_column=magic_lookup_column,
|
||||||
|
lookup_table=table,
|
||||||
|
where=" AND ".join(
|
||||||
|
"[{table}].[{column}] = [{lookup_table}].[{lookup_column}]".format(
|
||||||
|
table=self.name,
|
||||||
|
lookup_table=table,
|
||||||
|
column=column,
|
||||||
|
lookup_column=rename.get(column) or column,
|
||||||
|
)
|
||||||
|
for column in columns
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Drop the unnecessary columns and rename lookup column
|
||||||
|
self.transform(drop=set(columns), rename={magic_lookup_column: fk_column})
|
||||||
|
|
||||||
# And add the foreign key constraint
|
# And add the foreign key constraint
|
||||||
self.add_foreign_key(fk_column, table, "id")
|
self.add_foreign_key(fk_column, table, "id")
|
||||||
|
return self
|
||||||
|
|
||||||
def create_index(self, columns, index_name=None, unique=False, if_not_exists=False):
|
def create_index(self, columns, index_name=None, unique=False, if_not_exists=False):
|
||||||
if index_name is None:
|
if index_name is None:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue