繁体   English   中英

快速搜索SQLite数据库数千次的方法?

[英]Fastest way to search a SQLite database thousands of times?

首先提问

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

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

从简单地浏览纯文本文件切换到3倍加速了我的脚本,但我仍然认为它可以运行得更快。

先感谢您!


数据库

我有城市的名字,他们的邮政编码,坐标等我从国地名邮政编码的数据创建的SQLite数据库转储: 国地名邮政代码

该数据库为每个国家/地区提供一个表格(DE,US,GB等。总共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脚本尝试使用多种不同的搜索查询,例如:

  • 检查[邮政编码]是否与列完全匹配且[地名]是否与列完全匹配
  • 检查[邮政编码]是否与列完全匹配,并且[列名]是否完全匹配
  • 检查[邮政编码]是否与列完全匹配,并且[列名](按单词分隔)
  • 检查just [邮政编码]是否与列匹配

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所建议的那样,索引将是一个很好的起点,如果您至少没有关于邮政编码的索引,这将显着提高性能。

如果您已经有了这个或想进一步获得收益,我会考虑将Excel数据加载到您的SQLite数据库中,并尝试将其作为一个大查询来执行(由于匹配数量的原因,它需要对所有内容进行全表扫描)您试图获得的结果,但是一次执行可能并不算太糟糕。

如果这不能获得所需的结果或难以正确查询,则可以尝试将所有SQLite数据加载到Python中,并构建成字典,该字典将根据您需要查找的内容对数据进行排序,例如,一级字典对于国家/地区,每个国家/地区内都有所有邮政编码,每个国家/地区内都有该国家/地区的所有记录的列表。

基本上,这样做的主题是确保您针对哈希表类型结构(诸如数据库索引,python字典等排序的键值对)进行查找,或者是否确实要逐条记录地进行查找对于您的其他数据集中的每个记录。

对于拼写错误检测,您可以查看语音算法 (但每个算法仅针对特定语言而设计),因为特别是LIKE '%city%'即使使用索引也将保持低效。

此外,您可以尝试按国家/地区对excel数据进行重新排序(首先要求输入DE,然后要求输入美国,...)。 因此,Sqlite可以“集中”在一个表上,而不必一直切换,而且,Python的Sqlite-wrapper的预备语句缓存可以更有效地工作。

编辑:

准备好的语句是先前已解析和分析的SQL语句。 与始终创建和准备新语句相比,多次执行该命令效率更高。 Python的Sqlite-wrapper会缓存一些准备好的语句,如果再次使用完全相同的SQL语句字符串,则会重新使用它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM