IP地址定位区间的问题分析
以前写过一篇Oracle中关于IP地址定位的问题分析,最后引申出了一系列的问题。当时问题紧急严峻,抓取了10053事件定位源头,想出了一个解决妙法,还自鸣得意了下,结果忙活完之后看看行业里的解决方案都大体如此,我的心凉了半截。
我总是希望找到一些与众不同的点来解读这一类问题,结果在偶然的一天从MySQL这里找到了一些思路。
我先来分析下之前问题和一些收获。
需求是输入一个IP,能够根据IP从一个数据字典表里查询IP区段,返回IP对应的区域,这就是一个看起来很简单的IP地址定位的问题。
从系统负载方面,CPU的负载较高,而其中很大的一方面代价就是IP地址和数字(IP地址转换为数字)之间的转换和映射。
Buffer Gets指标极高,这个部分其实和整个语句的查取效果有关,如果没有找到匹配的数据,就会扫描更多的块。这个部分一个立竿见影的效果就是使用rownum的方式来截断,在这个基础上,和Oracle的朋友聊,其实也有一些改进措施的,这个部分对于极限优化来说可以参考,所以暂且放一放。
从索引的角度来考虑,Range Scan的方式总是会有优点和缺点,不可能把它同时结合起来达到一个最优的效果,换做那一个数据库都是如此,只能说有些回表的数据处理Oracle隐式(比如使用rowid))做好了,而MySQL里面可能需要单独处理。
问题就交代到这里,我今天想再次讨论这个问题是想从几个基础的问题开始来聊聊MySQL在这方面的优势,没错,是相比于Oracle的优势的地方。
首先我们来说说表结构的设计,如果在Oracle里面,当时设计的地址信息如下:
COLUMN_ID COLUMN_NAME DATA_TYPE DATA_LENGTH NULLABLE
---------- ------------------------------ --------------- ----------- ----------
1 IP_ID NUMBER(10,0) 22 N
2 IP_LEFT_LINE VARCHAR2(15) 15 N
3 IP_RIGHT_LINE VARCHAR2(15) 15 N
4 IP2NUM_LEFT_LINE NUMBER(10,0) 22 N
5 IP2NUM_RIGHT_LINE NUMBER(10,0) 22 N
6 COUNTRY VARCHAR2(20) 20 Y
7 PROVINCE VARCHAR2(20) 20 Y
8 CAPITAL VARCHAR2(20) 20 Y
里面对IP地址和IP地址转换后的数字都做了持久化,查询的逻辑相对就比较别扭了。
比如下面:B1是传入的IP地址,即一个字符串,会先转换为数字,然后做Range Scan。
SELECT IP_ID,COUNTRY,PROVINCE,CAPITAL
FROM SWD_IP2COUNTY
WHERE STRIPTOINT(:B1 ) BETWEEN IP2NUM_LEFT_LINE AND IP2NUM_RIGHT_LINE
如果换做MySQL,有哪些点需要考虑呢。
第一个考虑点还是数据类型,IP地址是一个字符串,我们是考虑使用varchar类型还是char呢。
假设一个IP地址为10.127.133.199,字符串的长度就是14位,最高设置为3*4+3=15位,这是第一点。
而如果我们存储了一个IP,则意味着这个工作还没有完成,我们还需要转换,所以还不如直接转换为数值,所以综合起来,其实我们实现这个需求,从简化的角度来看,其实不需要一个字符型,而是需要一个数值型即可。
那么问题来了,数值型数据类型其实是很丰富的,这一点和Oracle大大不同,Oracle里面很多开发,DBA都懒了,或者说Oracle内部已经做好了这种适配,数值精度也不需要更多考虑了,长度也不需要区别对待了,直接一个number类型,想调精度,就直接在这个基础上改,比如number(10,3),可以定义长度和精度。MySQL在这方面就分得比较轻,有支持0-128以内的tiny int,32767的smallint等,每一个数据类型都抠的很细。
所以在Oracle里面的豪气在这里就是粗放了,一定需要认真区别对待。
因为我们打算使用数值类型,最后我们选择了int(11),没有留出很富余的值是因为我们从设计的角度来考虑尽可能按需分配。
> create table ip_range(ip int(11) );
Query OK, 0 rows affected (0.01 sec)
我们插入两行值:
> insert into ip_range values(inet_aton('127.0.0.1')),(inet_aton('192.168.1.1'));
ERROR 1264 (22003): Out of range value for column 'ip' at row 2
结果发现竟然溢出了,SQL_Mode是严格模式。
好吧,看来我们太过于乐观了。逐个击破。
> insert into ip_range values(inet_aton('127.0.0.1'));
Query OK, 1 row affected (0.00 sec)
原来是这里的问题:
> insert into ip_range values(inet_aton('192.168.1.1'));
ERROR 1264 (22003): Out of range value for column 'ip' at row 1
这是因为int的数值类型其实分为有符号和无符号两种,区间分别是2147483647和4294967295,所以IP地址的需求我们只需要考虑无符号的情况,修改字段类型。
> alter table ip_range modify ip int(11) unsigned;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
然后再次插入就没有问题了。
> insert into ip_range values(inet_aton('192.168.1.1'));
Query OK, 1 row affected (0.00 sec)
这里需要提一下,就是对于IP地址的转换,MySQL已经提供了这个转换的方法,可以互相转换。分别是inet_ntoa(数值转为IP),inete_aton(IP转为数值)
> select (inet_ntoa(ip)) from ip_range;
+-----------------+
| (inet_ntoa(ip)) |
+-----------------+
| 127.0.0.1 |
| 192.168.1.1 |
+-----------------+
2 rows in set (0.00 sec)
有了这些铺垫,结合索引信息,实现这个需求问题 不大。
- 战斗民族开源神器ClickHouse:一款适合于构建量化回测研究系统的高性能列式数据库(二)
- Microsoft StreamInsight 构建物联网
- 利用 Microsoft StreamInsight 控制较大数据流
- HTML Agility Pack 搭配 ScrapySharp,彻底解除Html解析的痛苦
- 看看你是哪种级别的Python程序员(已跪)
- SignalR 在IE中无法工作 - Internet Explorer
- SQL Server 2012 中的 Service Broker功能的一些改进或增强
- 通用日志
- 数据包络分析教程
- 用JAVA的DEA算法衡量社交媒体页面的流行度
- 如何构建智能反垃圾邮件的WordPress插件
- 【深入研究】使用RNN预测股票价格系列一
- 【深入研究】使用RNN预测股票价格系列二
- 教你用一行Python代码实现并行(附代码)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- android实现截图并动画消失效果的思路详解
- 位运算判断奇偶数
- Kotlin之在Gradle中无参(no-arg)编译器插件的使用详解
- android实现常驻通知栏遇到的问题及解决办法
- Android仿微信键盘切换效果
- Android实现WIFI和GPRS网络的切换
- 在VS2010里快要疯掉的hello world
- gh0st源码分析与远控的编写(三)
- Android自定义View实现五星好评效果
- Android通过ViewModel保存数据实现多页面的数据共享功能
- Android自定义View实现炫酷进度条
- OpenSSL的VC编程 - MD5
- 详解AndroidStudio中代码重构菜单Refactor功能
- Android自定义View仿QQ运动步数效果
- Kotlin类型安全构建器的一次运用记录