![]() |
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
谢谢你的评论,我真的很感激。 目前,我们最终使用了缓存机制,并减少了昂贵的查询。 |
![]() |
hello_programmers · Mysql从其他表输出一列 1 年前 |
![]() |
Community wiki · 这个MySQL语句出了什么问题? 1 年前 |
![]() |
Community wiki · 优化从同一表中提取的多列的查询 1 年前 |
![]() |
Popo · Sql查询:返回数据库中不可用的where条件 2 年前 |
|
Hamdan Nuramdani · 对账单中一周内不同表中的数据求和 2 年前 |
|
Kugelfisch · 用php为数据库加密数据 2 年前 |