【问题标题】:How to properly implement indexing for use in variable LIKE statement with sqlite3?如何使用 sqlite3 正确实现用于变量 LIKE 语句的索引?
【发布时间】:2019-12-11 05:56:01
【问题描述】:

我正在尝试在两个表之间进行一些模糊匹配。 一个是我在本地存储的表(9,000 行),称为表 A。另一个存储为 sqlite db(200 万 + 行 csv),称为表 B。 基本上,我想将表 A 中的“CompanyNames”列与表 B 中的“CurrentEntityNames”列匹配,并使用它来将表 B 左连接到表 A。

我目前能够遍历 LIKE 语句,传递如下参数: (myNames 只是表 A 中的 CompanyNames 列作为列表)。

for index, name in enumerate(myNames):
        sql = 'SELECT * from "table" WHERE CurrentEntityName LIKE ?;'
        param =(name + '%%',)
        df = pd.read_sql_query(sql,engine, params=param)
        myresponses[index] = df

但是,我有两个问题: 1. 我意识到查询表 A 中的每一行可能不是很有效,因为目标是尽量减少与数据库的交互。 如果最好重组以减少查询,我该怎么做? 2. 添加基于 CurrentEntityName 的索引会加快速度吗?

对于方法 2,我尝试使用(在另一个 stackoverflow 答案中找到)添加索引

meta = sqlalchemy.MetaData()
meta.reflect(bind=engine)
table = meta.tables['table']
my_index = sqlalchemy.Index('nameIds', table.columns.get('CurrentEntityName'))

但我不确定在查询时如何实现这一点。

对于方法 1.,我已经看到了一些使用 conn 和 cursor 的示例,但实际上我不确定如何将这些与从引擎创建的数据库结合使用。 (我使用

加载了我的数据
for df in pd.read_csv("C://Users//SEAB//Downloads//Active_Corporations___Beginning_1800.csv", chunksize = chunksize, iterator = True):
    df = df.rename(columns={c:c.replace(' ', '')  for c in df.columns})
    df.index +=j
    i+=1
    df.to_sql('table', engine, if_exists = 'append')
    j= df.index[-1] + 1

在本教程中找到 [https://plot.ly/python/v3/big-data-analytics-with-pandas-and-sqlite/]

基本上,查询仍然很慢(9000 行可能需要超过 1 小时)。 我非常感谢任何建议或帮助。我是 sqlite3 的新手,所以我不知道很多。感谢您的理解。

【问题讨论】:

    标签: sqlite indexing sqlalchemy sql-like pandasql


    【解决方案1】:

    The rules for Sqlite 何时可以使用带有LIKE 的索引很多,但它可以做到。

    基本上,考虑到默认的不区分大小写的行为:您需要在左侧有一列 TEXT affinity。右侧需要是格式为“XXX%”的字符串文字(或者,如果语句使用sqlite3_prepare_v2() 编译,则为绑定到字符串的参数) - 即任何通配符之前的前导常量值。鉴于此,如果左侧列上有不区分大小写的索引,它可以重写查询以使用该索引,而不是查看每一行。

    来自交互式会话的一些示例:

    sqlite> CREATE TABLE ex(col1 TEXT, col2 TEXT COLLATE NOCASE);
    sqlite> CREATE INDEX ex_col1_idx ON ex(col1);
    sqlite> CREATE INDEX ex_col2_idx ON ex(col2);
    sqlite> EXPLAIN QUERY PLAN SELECT * FROM ex WHERE col1 LIKE 'foo%';
    QUERY PLAN
    `--SCAN TABLE ex
    sqlite> EXPLAIN QUERY PLAN SELECT * FROM ex WHERE col2 LIKE 'foo%';
    QUERY PLAN
    `--SEARCH TABLE ex USING INDEX ex_col2_idx (col2>? AND col2<?)
    sqlite> CREATE INDEX ex_col1_idx_nocase ON ex(col1 COLLATE NOCASE);
    sqlite> EXPLAIN QUERY PLAN SELECT * FROM ex WHERE col1 LIKE 'foo%';
    QUERY PLAN
    `--SEARCH TABLE ex USING INDEX ex_col1_idx_nocase (col1>? AND col1<?)
    sqlite> .parameter init
    sqlite> .parameter set ?1 'foo%'
    sqlite> EXPLAIN QUERY PLAN SELECT * FROM ex WHERE col1 LIKE ?;
    QUERY PLAN
    `--SEARCH TABLE ex USING INDEX ex_col1_idx_nocase (col1>? AND col1<?)
    

    如您所见,被搜索的索引列需要在表定义中明确指定不区分大小写的排序规则,或者具有明确不区分大小写的索引。

    在您的情况下,事情变糟的最大可能性是 Python sqlite 绑定如何准备与 execute 方法一起使用的语句 - 它是使用旧的 sqlite3_prepare() 还是新的 sqlite3_prepare_v2() API?如果我正在查看the right source file,它使用后者,所以这应该不是问题。

    【讨论】:

    • 你好!!!我非常感谢你的帮助。基本上我下载了 Sqlite 并像你一样做了 COLLATE Nocase 来添加索引,然后我用 Python 备份了数据库,我的查询现在运行得非常快!您的回答帮助我了解 Python sqlite3 只是 Sqlite 的一个接口,您可以正常执行 Sqlite 命令,只需对语法进行一些调整。我现在感觉不那么困惑了,我真的很高兴我终于可以运行查询了:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 2016-06-12
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    相关资源
    最近更新 更多