|
|
1
1
解决方法是获取btree/isam库并使用它(如Berkelydb)。使用isam这是一项微不足道的任务。 使用isam,您可以将起始键设置为数字,执行“查找下一个”,(查找大于或等于您的数字的块),如果不等于,您将“查找上一个”并检查该块。3-4次磁盘命中,shazam,瞬间完成。 好吧,这是个解决办法。 这里发生的问题是,没有“足够智能的优化器”的SQL在这种查询上做得很糟糕。 例如,您的查询:
它将“查看”所有“小于”1406658569的行。所有的行,然后扫描它们,寻找所有符合第二个条件的行。 对于一个3.5米的行表,假设“平均”(也就是说它在中间),欢迎使用1.75米的行表扫描。更糟的是,索引表扫描。理想情况下,MySQL将“放弃”和“只是”表扫描,因为它更快。 显然,这不是你想要的。 @Andomar的解决方案基本上是通过“网络”标准强制您“阻塞”到数据空间。有效地把你的桌子破成255块。因此,不扫描1.75米的行,而是扫描6800行,这是一个显著的改进,代价是打破网络边界上的障碍。 SQL中的范围查询没有任何错误。
通常是一个快速查询,因为优化器可以很容易地使用索引分隔行的范围。 但是,这不是您的查询,因为在本例中,您的范围不是主ID(startipnum)。 如果您“知道”您的块大小在某个范围内(例如,您的块中没有一个块的IP超过1000),则可以通过添加“where startipnum between ipnum-1000 and ipnum+1000”来阻止查询。这与提议的网络阻塞没有什么不同,但是这里您不必维护太多。当然,您可以通过以下方式学习:
了解您的最大范围是什么。 另一个选择,我已经看到,从来没有使用过,但实际上,嗯,这是完美的,是看看 MySql's Spatial Extensions 因为这就是事实。 这是专为地理信息系统应用而设计的,但是你在搜索范围内的东西,这是地理信息系统应用所做的很多工作。所以,这可能也是一个解决方案。 |
|
|
2
1
startip和endip应该是一个组合索引。MySQL不能在一个查询中对同一个表使用多个索引。 我不确定语法,但有点像 键(startipnum,endipnum) |
|
|
3
1
看起来您正在尝试查找IP地址所属的范围。问题是MySQL不能充分利用索引进行中间操作。索引在使用=操作时效果更好。 向查询中添加=操作的一种方法是 network part of the address 在桌子旁边。例如:
索引打开时
如果一个geoip块跨越多个网络类,则必须将其拆分为每个网络类一行。 |
|
|
4
1
根据您问题中的信息,我假设您所做的是从MaxMind®实现geoip®产品。我下载了免费版本的geoip®数据,将其加载到一个mysql数据库中,并做了一些快速的实验。 使用startipnum上的索引,查询执行时间从0.15到0.25秒不等。在startipnum和endipnum上创建复合索引不会更改查询性能。这让我相信您的性能问题是由于硬件不足、MySQL调优不当或两者兼而有之。我在其上运行测试的服务器有8g RAM,这远远超过了获得与索引文件仅28m相同的性能所需的内存。 我的建议是以下两个选项之一。
顺便说一句,您提出的两个查询是不等价的。中间运算符包含在内。第二个查询将需要使用<=>=运算符来等效于使用between运算符的查询。 |
|
|
5
0
也许您想看看对表进行分区。这项功能从MySQL5.1开始就可用了,因此您没有指定要使用的版本,如果您坚持使用旧版本,这可能对您不起作用。 由于已知IP地址的可能值范围(至少对于IPv4),您可以将表分解为多个大小相同的分区(如果数据分布不均匀,甚至可能不相等)。有了这个MySQL,可以很容易地跳过表的大部分,如果仍然需要的话,可以加快扫描速度。 参见 MySQL manual on partitioning 以获取可用的选项和语法。 |
|
|
6
0
谢谢你的评论,我真的很感激。 目前,我们最终使用了缓存机制,并减少了昂贵的查询。 |
|
|
Bard.Mus · 迁移后的数据库字符集环境 1 年前 |
|
Efannnnnn · 将Id数据存储到任何页面 1 年前 |
|
|
yooooo · 用于在块中删除的存储过程-LOOP未执行 1 年前 |
|
John Beasley · 更新一定数量记录的连续日期 1 年前 |
|
|
ColinM · MySQL以前的结果查询返回不正确的值 1 年前 |
|
Sergey_Z · MySQL只需无条件连接2个表和交叉连接 1 年前 |