python - 搜索 SQLite 数据库数千次的最快方法?

标签 python sqlite subquery geonames

先问问题

如何尽快搜索我的 SQLite 数据库?

我是否应该解析 Excel 中所有 60,000 行的地址数据,将它们加载到列表中,然后立即搜索所有这些数据?

从简单地查看纯文本文件开始,我的脚本速度提高了 3 倍,但我仍然认为它可以更快。

提前谢谢您!


数据库

我有一个包含城市名称、邮政编码、坐标等的 SQLite 数据库,该数据库是我根据 Geonames 的邮政编码数据转储创建的: Geonames Postal Codes

该数据库针对每个国家(德国、美国、英国等,总共 72 个)都有一个表,每个表都有几十到数万行,格式如下:

country code      : iso country code, 2 characters
postal code       : varchar(20)
place name        : varchar(180)
admin name1       : 1. order subdivision (state) varchar(100)
admin code1       : 1. order subdivision (state) varchar(20)
admin name2       : 2. order subdivision (county/province) varchar(100)
admin code2       : 2. order subdivision (county/province) varchar(20)
admin name3       : 3. order subdivision (community) varchar(100)
admin code3       : 3. order subdivision (community) varchar(20)
latitude          : estimated latitude (wgs84)
longitude         : estimated longitude (wgs84)
accuracy          : accuracy of lat/lng from 1=estimated to 6=centroid

工作流程

现在我当前的 Python 脚本如下:

  • 读取 Excel 文件中的行
  • 解析地址和位置数据(中间有很多其他不相关的内容)
  • 在 SQLite 数据库中搜索匹配项
  • 将 SQLite 数据库中匹配行的信息写入 .CSV 文件

Excel 文件大约有 60,000 行,每行都会遍历我的整个 Python 脚本(上述过程)。

我的地址数据非常不一致,包含邮政编码、城市名称和国家/地区名称。有时所有这些数据都位于 Excel 行中,有时则不然。它还带有许多拼写错误和备用名称。

由于数据非常不一致,而且有时人们输入的邮政编码和城市不匹配,所以我目前让我的 Python 脚本尝试一堆不同的搜索查询,例如:

  • 检查[邮政编码]是否与列完全匹配并且[地点名称]是否与列完全匹配
  • 检查[邮政编码]是否与列完全匹配以及列中的[地名]
  • 检查[邮政编码]是否与列中的完全匹配以及列中的[地名](按单词分割)
  • 检查[邮政编码]是否与列匹配

Python 脚本

这是 Python 脚本的部分。正如您所看到的,这似乎效率很低:

if has_country_code == True:
    not_in_list = False
    country = country_code.lower()+"_"
    print "HAS COUNTRY"
    if has_zipcode == True and has_city_name == True:
        print "HAS COUNTRY2"
        success = False

        try:
            curs = conn.execute("SELECT * FROM "+country+" WHERE postal_code = ? AND place_name = ? COLLATE NOCASE", (zipcode, city,))

            for row in curs:
                success = True
                break   
        except:
            not_in_list = True
            success = True

        if success != True:  
            curs = conn.execute("SELECT * FROM "+country+" WHERE postal_code = ? AND place_name LIKE ? COLLATE NOCASE", (zipcode,"%"+city+"%",))

            for row in curs:
                success = True
                break

        if success != True:
            newCity = ""  
            newCity = filter(None,re.split('[; / ( ) - ,]',city))
            questionMarks = ",".join(["?" for w in newCity])


            curs = conn.execute("SELECT * FROM "+country+" WHERE postal_code = ? AND place_name IN ("+questionMarks+") COLLATE NOCASE", ([zipcode]+newCity))

            for row in curs:
                success = True
                break   


        if success != True:
            curs = conn.execute("SELECT * FROM "+country+" WHERE postal_code = ? COLLATE NOCASE", (zipcode,))

            for row in curs:
                success = True
                break   


        if success != True:

            curs = conn.execute("SELECT * FROM "+country+" WHERE place_name = ? COLLATE NOCASE", (city,))

            for row in curs:
                success = True
                break   

        if success != True:

            curs = conn.execute("SELECT * FROM "+country+" WHERE place_name LIKE ? COLLATE NOCASE", ("%"+city+"%",))

            for row in curs:
                success = True
                break

        if success != True:
            newCity = ""  
            newCity = filter(None,re.split('[; / ( ) - ,]',city))
            questionMarks = ",".join(["?" for w in newCity])


            curs = conn.execute("SELECT * FROM "+country+" WHERE place_name IN ("+questionMarks+") COLLATE NOCASE", (newCity))

            for row in curs:
                success = True
                break

        if success != True:     
            newCity = ""                   
            newCity = filter(None,re.split('[; / ( ) - ,]',city))
            newCity.sort(key=len, reverse=True)
            newCity = (["%"+w+"%" for w in newCity])

            for item in newCity:
                curs = conn.execute("SELECT * FROM "+country+" WHERE place_name LIKE (?) COLLATE NOCASE", (item,))

                for row in curs:
                    success = True
                    break
                break   





    if has_city_name == True and has_zipcode == False:        
        try:
            curs = conn.execute("SELECT * FROM "+country+" WHERE place_name = ? COLLATE NOCASE", (city,))

            for row in curs:
                success = True
                break   
        except:
            not_in_list = True
            success = True

        if success != True:
            curs = conn.execute("SELECT * FROM "+country+" WHERE place_name LIKE ? COLLATE NOCASE", ("%"+city+"%",))

            for row in curs:
                success = True
                break

        if success != True:
            newCity = ""  
            newCity = filter(None,re.split('[; / ( ) - ,]',city))
            questionMarks = ",".join(["?" for w in newCity])


            curs = conn.execute("SELECT * FROM "+country+" WHERE place_name IN ("+questionMarks+") COLLATE NOCASE", (newCity))

            for row in curs:
                success = True
                break 



        if success != True:     
            newCity = ""                   
            newCity = filter(None,re.split('[; / ( ) - ,]',city))
            newCity.sort(key=len, reverse=True)
            newCity = (["%"+w+"%" for w in newCity])

            for item in newCity:
                curs = conn.execute("SELECT * FROM "+country+" WHERE place_name LIKE (?) COLLATE NOCASE", (item,))

                for row in curs:
                    success = True
                    break
                break   




    if has_city_name == False and has_zipcode == True:
        try:
            curs = conn.execute("SELECT * FROM "+country+" WHERE postal_code = ?", (zipcode,))

            for row in curs:
                success = True
                break

        except:
            not_in_list = True
            success = True

最佳答案

这可能是您可能需要尝试不同方法,然后查看每种方法是否足够快的情况之一。正如 @Philip 建议的那样,索引将是一个很好的起点,如果您至少还没有邮政编码的索引,这应该会显着提高性能。

如果你已经有了这个或者想尝试获得更多 yield ,我会考虑将 Excel 数据加载到你的 SQLite 数据库中,并尝试将其作为一个大查询来执行(由于您想要获得的匹配数,但执行一次可能不会太糟糕。

如果这没有得到你想要的结果,或者事实证明很难得到正确的查询,你可以尝试将所有 SQLite 数据加载到 Python 中,并构建到字典中,字典将根据你需要查找的内容对数据进行排序,例如:国家/地区的一级字典,每个国家/地区内都有所有邮政编码,每个邮政编码内都有该国家/地区/邮政编码的所有记录的列表。

基本上,这个主题是确保您正在针对哈希表类型结构(排序的键值对,例如数据库索引、Python 字典等)进行查找,或者如果您确实逐条记录地进行查找不要对其他数据集中的每条记录执行此操作。

关于python - 搜索 SQLite 数据库数千次的最快方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18143254/

相关文章:

php - Php SQLITE 中的分页

ios - sqlite3_open() 中的参数

mysql - 对查询中的多个 IF 求和

python - 是否有支持 xmltype 列的 Python Oracle 包装器?

python - 为什么 py 和 python 给出不同的结果?

python - 如何配置 Tkinter 列表框以禁用状态保持所选项目突出显示

android - CREATE 中的错误消息 - 未在 place_info 表中插入记录

jpa - 如何对 JPA 查询的子查询施加 LIMIT?

MySql 子查询作为列和别名

Python - 多次尝试访问 API 时发生错误