【问题标题】:What is the most appropriate data type for storing an IP address in SQL server? [duplicate]在 SQL Server 中存储 IP 地址最合适的数据类型是什么? [复制]
【发布时间】:2010-11-05 13:17:33
【问题描述】:

在 SQL Server 中存储 IPv4 地址时最推荐的数据类型应该是什么?

或者也许有人已经为它创建了一个用户 SQL 数据类型(.Net 程序集)?

我不需要排序。

【问题讨论】:

  • 不要忘记 IPv6 现在就在这里。今天在解析网络服务器日志时,有时会遇到一个 v6 地址...

标签: sql sql-server types ip-address ipv4


【解决方案1】:

引用this:

将 IP 地址存储在 CHAR(15) 列中。根据您存储的数据量,这可能会非常浪费(为什么我们需要存储点?)。我

【讨论】:

  • "这可能很浪费" 除非您存储世界上所有的 IP,否则我认为最好用点存储它。 “过早的优化是万恶之源”
  • 您需要存储点,否则您将无法区分 127.1.1.10 和 127.1.11.0 之间的区别,两者都将存储为 1271110。我想您可以将其存储为 4 个单独的byte 字段,但除非您真的担心为大量数据节省空间,否则我认为不值得付出额外的努力(以及将其重新组合在一起的处理)。
  • "12121212" 是 12.12.12.12 或 12.121.2.12 还是 12.121.21.2 或 ....
  • @tekBlues:“过早优化”是很好的数据库设计。
  • 请记住在引用外部资源时添加引用。
【解决方案2】:

我通常只对 IPv4 地址使用 varchar(15) - 但是对它们进行排序很麻烦,除非你填充零。

我过去也将它们存储为 INT。 System.Net.IPAddress 有一个 GetAddressBytes 方法,它将 IP 地址作为代表 IP 地址的 4 个字节的数组返回。您可以使用以下 C# 代码将 IPAddress 转换为 int...

var ipAsInt = BitConverter.ToInt32(ip.GetAddressBytes(), 0);

我之所以使用它,是因为我必须做大量的重复地址搜索,并且希望索引尽可能小且快。然后要将地址从 int 中拉回到 .net 中的 IPAddress 对象中,请使用 BitConverter 上的 GetBytes 方法将 int 作为字节数组获取。将该字节数组传递给IPAddressconstructor,它接受一个字节数组,最后您将返回您开始使用的IPAddress

var myIp = new IPAddress(BitConverter.GetBytes(ipAsInt));

【讨论】:

  • 如果要填充 ip,使用 CHAR(15) 会更有意义
  • y 不使用 varchar 并忘记零?
  • 用零填充 IP 地址可以使其成为不同的 IP 地址。 010.001.001.100 与 10.1.1.100 不同。在八位字节中的值前面有一个零表示该八位字节正在以八进制写入。存储 IP 地址的正确方法是解析它们的各种可能表示形式并将它们存储为二进制值(32 位或 128 位,具体取决于它们是 IPv4 还是 IPv6 地址)。
  • 仅供参考,IPAddress.Parse 在字符串上使用时可能非常有用。另请注意,在 .NET 4.0 中,Microsoft 添加了一个新函数 GetAddressBytes,您无需将其转换为字节数组,并且可以使用支持它的构造函数之一来创建简单的函数。
  • RE:对 IP 地址进行排序。在 SQL Server 2008 中,您可以使用 hierarchyid 来帮助解决此问题 stackoverflow.com/questions/1038950/…
【解决方案3】:

IPV4?诠释?还是 tinyint x 4?

这真的取决于它是否只是存储和检索,或者它是否将成为一个范围搜索条件。

【讨论】:

    【解决方案4】:

    将 IPv4 地址存储为 binary(4) 最符合其所代表的内容,并且可以轻松进行子网掩码式查询。但是,如果您实际上是在文本表示之后,它需要转换输入和输出。在这种情况下,您可能更喜欢字符串格式。

    顺便说一句,如果您将存储为字符串,一个很少使用的 SQL Server 函数是PARSENAME,它可能会有所帮助。不是为 IP 地址设计的,但非常适合它们。下面的调用将返回“14”:

    SELECT PARSENAME('123.234.23.14', 1)
    

    (编号从右到左)。

    【讨论】:

    • 如果需要,您还可以创建 UDF 以使用点分十进制表示法处理这些数据......也许既可以用于输入也可以用于检索。
    • 是的。或者,如果使用 ORM,则可以轻松完成此转换 - 例如,(N)Hibernate 中的 UserType。
    • 如何进行选择以使其返回单个 int?还有什么成本更多的空间,单个 sql int 或二进制(4)?所以我可以使用 IPAddress 的构造函数(以 long 作为参数)?查看@我的回答:stackoverflow.com/questions/1038950/3445015#3445015
    • @DavidM 为什么不是整数?你能解释一下存储为二进制而不是整数的性能优势吗?
    • 我没说有。我说这是数据最真实的表现。
    【解决方案5】:

    由于IP地址有32位,你可以用LONG来存储数值吗?
    它不会像使用 VARCHAR 那样浪费空间,但是每次使用它之前,您都必须将其解码回 IP,而且延迟和开销可能不值得。

    【讨论】:

    【解决方案6】:

    我在制作四个 smallint(或任何您喜欢的小整数数据类型)列方面取得了一些成功——每个八位字节一个。然后,您可以创建一个视图,将它们组合成一个字符字符串(用于显示),或者您可以编写简单的运算符来确定谁在哪个子网中等等。

    它非常快(前提是您进行了正确的索引),并且还允许非常简单的查询(没有字符串操作!)。

    【讨论】:

      【解决方案7】:

      不要忘记 IPv6 - 如果需要存储它们,则需要更多空间 - 128 位与 IPv4 的 32 位相比。

      我会选择 bigint,不过您需要一些帮助代码来转换为人类友好的版本。

      【讨论】:

        【解决方案8】:

        对于节省空间的存储以及要处理值(匹配或与范围比较)时,我使用int。 IP 地址实际上只是一个 32 位值。

        对于您只想存储值以查看它的简单解决方案,我使用varchar(15) 来存储 IP 地址的字符串表示形式。

        【讨论】:

          【解决方案9】:

          我最喜欢的articles 之一谈到了为什么不应该使用正则表达式来解析 IP 地址。他们谈论的大部分内容实际上是在解释为什么您应该非常小心 IP 地址的文本表示。我建议您在决定在数据库中使用什么数据类型之前阅读它,并且可能还考虑您的应用程序将要执行的任何处理(即使这篇文章是关于 Perl 的,它对任何语言都很有用)。

          我认为最终一个 32 位数据类型(或四个 8 位数据类型)将是最好的选择。

          【讨论】:

          • 你不觉得有点断章取义吗?他将它们序列化到数据库中——无论他选择什么数据库数据类型或格式,他都将控制这种转换。这篇文章只是迂腐——我没有看到它所谈论的任何实际应用。
          【解决方案10】:

          关于已接受答案中的此评论

          除非你填充,否则对它们进行排序是一件很痛苦的事情 零。

          这是 SQL Server 2008 的技巧(来自 this book 中的 Itzik Ben-Gan)

          with ip_addresses as
          (
          SELECT '131.33.2.201' AS ip_address UNION ALL
          SELECT '2.12.4.4' AS ip_address UNION ALL
          SELECT '131.33.2.202' AS ip_address UNION ALL
          SELECT '2.12.4.169' AS ip_address UNION ALL
          SELECT '131.107.2.201' AS ip_address 
          )
          select ip_address
          from ip_addresses
          ORDER  BY CAST('/' + ip_address + '/' AS hierarchyid)
          

          返回

          ip_address
          -------------
          2.12.4.4
          2.12.4.169
          131.33.2.201
          131.33.2.202
          131.107.2.201
          

          【讨论】:

          【解决方案11】:

          这取决于你的目的。如果您想要最好的存储和可能的性能,并且在大多数情况下,将其存储为 int,将其存储为 varchar 等会比简单的无辜 int 花费更多的性能。
          您也可以通过将搜索参数设置为所需的 int 来按 IP 进行搜索。

          有一个属性IPAddress.Address 但它已经过时了,我不知道为什么,因为如果您不需要对 IP 类进行排序或控制,最好的方法是将其存储为无符号整数(具有0xffffffff 的最大值等于十进制表示的 255.255.255.255
          使用 EF Core,您可以使用转换器将其自动转换为IPAddress

          IPAddress 类也有一个接受长参数的构造函数。

          根据 VS 调试器可视化工具,IPAddress 类本身将其内部变量存储为一个数字(不是字节数组)。

          阅读有关在 MS SQL Server 中存储单元的解决方法的更多信息:

          【讨论】:

          • 我真的不明白你的第一段..你是说 store as int 还是不?
          • @Pacerier,存储为int
          【解决方案12】:

          我在这里阅读了很多类似的问题,但没有一个回复提到其他人的第一答案:“对于 IPv4 地址,您可能希望将它们存储为 int unsigned 并使用 INET_ATON () 和 INET_NTOA() 函数从其数值返回 IP 地址,反之亦然。”我想这就是我要在我的数据库中使用的东西,除非我决定使用上面提到的 php 函数。

          【讨论】:

          • SQL Server 没有这样的功能
          【解决方案13】:

          我是 @php,sql 的新手,但我认为在 sql db 中存储内容的最快方法是将其转换为 int 值并另存为 int。

          我在php中使用了函数-

          function ip_convert() {
              $ip = $_SERVER['REMOTE_ADDR'];
              $intip = str_replace(".","0",$ip);
              return $intip;
          }
          

          然后我只是用零替换所有点。 然后,如果我需要使用 sql 中的这个 ip .. if($ip == ip_convert())

          但这只有在你使用 PHP 的情况下。

          【讨论】:

          • 这与 SQL Server 有什么关系?
          • 1.0.100.1 --> 10001001 100.1.0.1 --> 10001001 除非您在某处进行零填充,否则这似乎是一个非常糟糕的主意请注意,您可以将点分符号转换为 32 位整数(只要您确定它始终是 IPv4 地址,而不是主机名或 IPv6 地址)
          猜你喜欢
          • 2011-12-30
          • 1970-01-01
          • 1970-01-01
          • 2011-10-05
          • 2010-09-17
          • 2012-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多