问题背景

数据库审核过程中发现有存储ip的字段类型为varchar(50)、想到postgresql有专门的存储ip类型。然而存在即合理、所以主要对比varchar和inet存储ip的不同。

网络地址类型

名字 存储空间 描述
cidr 7 或 19 字节 IPv4 或 IPv6 网络
inet 7 或 19 字节 IPv4 或 IPv6 主机和网络
macaddr 6 字节 MAC 地址

cidr默认是存储了子网掩码、而inet可以不存储、macaddr用于存储MAC地址

创建测试表、生成测试数据

postgres=# create table t_ip_test(c_bh char(32),ip_start inet,ip_end inet);
CREATE TABLE
postgres=# insert into t_ip_test values(replace(CAST(uuid_generate_v4()as varchar), '-', ''),'192.168.1.1','192.230.254.254');
INSERT 0 1
--创建测试表
postgres=# create table t_ip(c_bh char(32),inet_ip inet,c_ip varchar (50));
CREATE TABLE
--生成测试数据192.168.1.1-192.230.254.254连续的ip
postgres=# insert into t_ip
postgres-# select
postgres-# replace(CAST(uuid_generate_v4()as varchar), '-', ''),
postgres-# generate_series(0,ip_end-ip_start)+ip_start as inet_ip,
postgres-# (generate_series(0,ip_end-ip_start)+ip_start) as c_ip
postgres-#from t_ip_test;
INSERT 0 4128254
--添加主键
postgres=# alter table public.t_ip ADD PRIMARY KEY ("c_bh");
ALTER TABLE

总共生成400W+数据

创建索引

--inet类型
postgres=# create index idx_t_ip_inet_ip on t_ip(inet_ip);
CREATE INDEX
--varchar类型
postgres=# create index idx_t_ip_c_ip on t_ip(c_ip);
CREATE INDEX

对比表大小、索引大小

--表大小
postgres=# select pg_size_pretty(pg_relation_size('t_ip'));
pg_size_pretty
----------------
365 MB
(1 row)
--索引大小
postgres=# select indexrelname, pg_size_pretty(pg_relation_size(indexrelname::varchar))
postgres-# from pg_stat_user_indexes where schemaname = 'public';
  indexrelname   | pg_size_pretty
------------------+----------------
t_ip_pkey       | 233 MB
idx_t_ip_inet_ip | 88 MB
idx_t_ip_c_ip   | 159 MB
(3 rows)

可以看到idx_tip_cip比idx_t_ip_inet_ip大了接近一倍

网络地址能自动验证ip正确性

--测试192.168.1.256
postgres=# insert into t_ip(c_bh,inet_ip,c_ip) values(replace(CAST(uuid_generate_v4()as varchar), '-', ''),'192.168.1.256','192.168.1.255');
ERROR: invalid input syntax for type inet: "192.168.1.256"
LINE 1: ...lace(CAST(uuid_generate_v4()as varchar), '-', ''),'192.168.1...'

postgres=# insert into t_ip(c_bh,inet_ip,c_ip) values(replace(CAST(uuid_generate_v4()as varchar), '-', ''),'192.168.1.255','192.168.1.256')
postgres-# ;
INSERT 0 1

可以看到inet类型能够自动识别IP是否合理、而varchar会将错误的ip插入数据库

inet类型查询某个段、某个范围的ip可以走索引

--查询某个段的ip 使用inet类型
postgres=# explain analyze select c_bh,inet_ip,c_ip from t_ip where inet_ip <<= inet '192.168.12/24';
                                                        QUERY PLAN                                                        
----------------------------------------------------------------------------------------------------------------------------
-
Index Scan using idx_t_ip_inet_ip on t_ip (cost=0.43..17.98 rows=161 width=58) (actual time=0.054..0.659 rows=256 loops=1)
  Index Cond: ((inet_ip >= '192.168.12.0/24'::inet) AND (inet_ip <= '192.168.12.255'::inet))
  Filter: (inet_ip <<= '192.168.12.0/24'::inet)
Planning time: 1.531 ms
Execution time: 1.128 ms
(5 rows)


--查询某个段的ip 使用varchar类型
postgres=# explain analyze select c_bh,inet_ip,c_ip from t_ip where c_ip like '192.168.12.%';
                                              QUERY PLAN                                              
----------------------------------------------------------------------------------------------------------
Seq Scan on t_ip (cost=0.00..98381.98 rows=413 width=58) (actual time=0.761..1063.944 rows=256 loops=1)
  Filter: ((c_ip)::text ~~ '192.168.12.%'::text)
  Rows Removed by Filter: 4127998
Planning time: 0.519 ms
Execution time: 1064.433 ms
(5 rows)

--查询某个范围的ip inet类型
postgres=# explain analyze select c_bh,inet_ip,c_ip from t_ip where inet_ip >= inet '192.230.253.200' and inet_ip <'192.230.254.7';
                                                      QUERY PLAN                                                      
--------------------------------------------------------------------------------------------------------------------------
Index Scan using idx_t_ip_inet_ip on t_ip (cost=0.43..9.69 rows=63 width=58) (actual time=0.042..0.181 rows=63 loops=1)
  Index Cond: ((inet_ip >= '192.230.253.200'::inet) AND (inet_ip < '192.230.254.7'::inet))
Planning time: 0.378 ms
Execution time: 0.324 ms
(4 rows)

--使用varchar类型好像并没有什么好的办法查询一个范围

在inet类型上面创建btree索引、可以用上索引。

inet类型针对网络类型的操作更丰富(<、<=、=、>...)

--对ip做加减
postgres=# select inet'192.168.1.1'+100;
  ?column?  
---------------
192.168.1.101
(1 row)

--查询两个ip之间有多少个ip
postgres=# select inet'192.168.2.1'-inet'192.168.1.1';
?column?
----------
    256
(1 row)

--减去100个ip后的ip
postgres=# select inet'192.168.1.254'-100;
  ?column?  
---------------
192.168.1.154
(1 row)

masklen:获取子网掩码长度

--inet获取子网掩码
postgres=# select masklen('192.168.1.1');
masklen
---------
    32
(1 row)

postgres=# select masklen('192.168.1.1/24');
masklen
---------
    24
(1 row)

网络类型更多操作连接

结语

推荐使用网络地址存储ip、PostgreSql提供的网络数据类型有以下优势:

1.创建索引更省空间

2.能够自动校验ip的正确

3.统计某段或者某个区间可以走索引、而varcahr并不能很好的统计某个区间

4.在做统计的时候网络类型操作更加丰富、对ip做简单的加减。

postgresql-数据库网络地址存储探索的更多相关文章

  1. vivo数据库与存储平台的建设和探索

    本文根据Xiao Bo老师在"2021 vivo开发者大会"现场演讲内容整理而成.公众号回复[2021VDC]获取互联网技术分会场议题相关资料. 一.数据库与存储平台建设背景 以史 ...

  2. 从运维的角度分析使用阿里云数据库RDS的必要性--你不应该在阿里云上使用自建的MySQL/SQL Server/Oracle/PostgreSQL数据库

    开宗明义,你不应该在阿里云上使用自建的MySQL or SQL Server数据库,对了,还有Oracle or PostgreSQL数据库. 云数据库 RDS(Relational Database ...

  3. 基于telegraf+influxdb+grafana进行postgresql数据库监控

    前言 随着公司postgresql数据库被广泛应用,尤其是最近多个项目在做性能测试的时候都是基于postgresql的数据库,为了确定性能瓶颈是否会出现在数据库中,数据库监控也被我推上了日程.在网上找 ...

  4. postgresql数据库varchar、char、text的比较

    名字 描述character varying(n), varchar(n) 变长,有长度限制character(n), char(n) 定长,不足补空白text 变长,无长度限制简单来说,varcha ...

  5. Linux 下的 PostgreSQL 数据库+文件通用自动备份脚本

    由于 Odoo(原名 OpenERP)自 8.0 以来会生成 CSS,并把附件存储在文件系统中,因此以前单纯备份数据库的脚本已经不够用了.出于实际部署的考虑,我专门写了个较为通用的 Odoo 备份脚本 ...

  6. odoo开发笔记 -- odoo和postgresql数据库导入相关

    odoo数据库 导入.导出 首先odoo框架下postgresql数据库中,表结构的存储方式: 存在id(小写),并没有所谓的外部ID 例如数据库中的国家表:模块名_tb_country   (注意: ...

  7. Windows下Postgresql数据库的下载与配置方法

    注意下载的是二进制版,不是带Windows Installer的,即绿色版本 http://www.enterprisedb.com/products-services-training/pgbind ...

  8. postgresql数据库中对重复数据的处理

    我们在使用postgresql数据库的时候,如果一张数据表在未做任何约束的情况下,很可能会出现几条完全一样的数据,即重复数据.如下图所示: 那么如果我们要删除其中的2条该怎么办呢?第一种我们可以清空表 ...

  9. PostgreSQL数据库资料(转)

    PostgreSQL数据库资料 转自:http://blog.csdn.net/postgrechina/article/details/49132791 推荐书籍: 概念书籍: <Postgr ...

随机推荐

  1. form 表单添加 enctype ="multipart/form-data" 属性后后台接收中文乱码

    解决办法: new String( request.getParameter("title").getBytes("ISO-8859-1"),"utf ...

  2. oracle常用函数速记

    1.截断中文字符串 CREATE OR REPLACE function cn_cutstr(v_str varchar2,v_len number) return varchar2 IS v_i n ...

  3. Ckeditor上传图片返回的JS直接显示出来,未执行!!!

    Ckeditor上传图片网上有很多教程. 下面是我今天下午遇到的一个坑...自己挖的坑. 在conotroller里 我开始习惯性的 response.setContentType("app ...

  4. HDU1254 推箱子(BFS) 2016-07-24 14:24 86人阅读 评论(0) 收藏

    推箱子 Problem Description 推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运工,搬运工的工作就是把箱子推到指定的位置,注意,搬运工只能推 ...

  5. [Java]ArrayList集合的contains方法

    用到集合ArrayList时经常会用到里面自带的方法boolean contains(Object o);此方法用于判断集合里面是否包含元素o,现在讨论下在Object类型为类类型的时候的情况: cl ...

  6. Delphi XE10 dxLayoutControl 控件应用指南

    https://www.cnblogs.com/Bonny.Wong/p/7440288.html DevExpress VCL套件是一套非常强大的界面控件,可惜关于Delphi开发方面的说明太少,有 ...

  7. Android Sqlite 简单SQL语句

    --- 创建表 create table student(_id integer primary key autoincrement, name text); --- 查询全部 select _id, ...

  8. linux与unix时间戳互转

    linux与unix时间戳互转 今天在消费kafka数据时遇到了这样一个问题,kafka数据中所有的数据时间戳格式都是unix上时间戳的格式,例如:1505786829101,看到这个时间戳真的是头都 ...

  9. python 检索一个目录下所有的txt文件,并把文件改为.log

    检索一个目录及子目录下所有的txt文件,并把txt文件后缀改为log: import os f_path = r'C:\Users\PycharmProjects\mystudy\Testfolder ...

  10. Asp.net WebForm 中无法引用App_Code文件夹下的类

    在VS2013中新建asp.net webform应用程序,手动添加"APP_Code"文件夹并新建类文件,发现这些类无法在APP_Code文件夹以外被引用. 解决办法: 选中类文 ...