博士后——不要这样做

2022-02-13 20:52:27

SQL_ASCII表示";没有转换";用于所有编码转换函数。也就是说,原始字节被简单地视为处于新编码中,接受有效性检查,而不考虑它们的含义。除非格外小心,否则SQL_ASCII数据库通常会混合存储许多不同的编码,无法可靠地恢复原始字符。

如果您的输入数据已经处于未标记的编码(例如IRC信道日志或非MIME兼容电子邮件)的无希望混合中,那么SqLYASCII可能是有用的,但考虑首先使用ByTeA,或者是否可以自动检测UTF8,并假设非UTF8数据在某些特定的编码中,例如Win 1252。

在尝试连接到服务器之前,使用--password或-W标志将告诉psql提示您输入密码,因此您';即使服务器没有';我不需要。

它';s从来都不是必需的,好像服务器确实需要密码,psql会提示您输入密码,在设置权限时可能会非常混乱。如果你';将-W重新连接到一个配置为允许您通过对等身份验证访问的服务器,您可能会认为它';当密码真的不存在时,它需要密码';t、 如果用户你';以不'的身份重新登录;没有设置密码,或者在提示您时输入了错误的密码';我仍然会登录并认为你有正确的密码,但你赢了';无法从其他客户端(通过本地主机连接)或以其他用户身份登录。

几乎从来没有。这将节省到服务器的往返时间,但是';关于这件事。

规则非常强大,但它们没有';不要做他们看起来像做的事。他们看起来像';我们有一些条件逻辑,但他们实际上重写了一个查询来修改它或向它添加额外的查询。

从不虽然重写器是视图的一个实现细节,但没有理由直接撬起这个盖板。

表继承是fad的一部分,在fad中,数据库与面向对象代码紧密耦合。事实证明,把紧密联系在一起的事情';实际上并不能产生预期的结果。

从来没有……几乎没有。既然表分区是本机完成的,那么表继承的常见用例已经被一个本机特性所取代,该特性可以处理元组路由等,而无需定制代码。

如果需要时态_表扩展,并且希望用它来代替缺乏SQL 2011支持的行版本控制,那么极少数例外情况之一就是时态_表扩展。表继承将提供一个小的快捷方式,而不是使用UNION ALL来获取历史行和当前行。即便如此,在使用父表时,也应该警惕警告。

唐';t使用NOT IN,或NOT和IN的任何组合,例如NOT(x IN(选择…)。

(如果你认为你不想加入(选择…),那么你应该重写为使用NOT EXISTS。)

从列不在的foo中选择*(从条中选择x);——如果bar的任何值为0,则返回0行。x是空的

这是因为如果col=1,col IN(1,null)返回TRUE,否则返回null(即它永远不会返回FALSE)。由于NOT(TRUE)为FALSE,但NOT(NULL)仍然为NULL,因此NOT(col IN(1,NULL))在任何情况下都不可能返回TRUE(这与col NOT IN(1,NULL)相同)。

2.由于上述第1点,不在(选择…)没有很好地优化。特别是,规划者可以';t将其转换为反连接,因此它要么成为散列子平面,要么成为普通子平面。散列子计划速度很快,但规划器只允许对小的结果集使用该计划;简单的子平面非常慢(实际上是O(N²))。这意味着性能在小规模测试中看起来不错,但一旦超过尺寸阈值,性能就会降低5个或更多数量级;你不想发生这种事。

不在(列表、列表、值等)通常是安全的,除非列表中可能有空值(通过参数或其他方式)。所以它';当从查询结果中排除特定的常量值时,有时使用它是自然的,甚至是明智的。

PostgreSQL将表、列、函数和其他所有名称折叠为小写,除非它们';re";双引号";。

所以create table Foo()将创建一个名为Foo的表,而create table";酒吧";()将创建一个名为Bar的表。

这些select命令将起作用:select*from Foo,select*from Foo,select*from";酒吧";。

这些将以"失败;没有这样的桌子";:从"中选择*;Foo";,从栏中选择*,从栏中选择*。

这意味着,如果在表或列名中使用大写字符,则必须始终对其进行双引号,或永远不要对其进行双引号。那';手工操作已经够烦人的了,但是当你开始使用其他工具访问数据库时,有些工具总是引用所有的名字,有些则不';t、 这让人很困惑。

坚持使用a-z、0-9和下划线作为名称,你永远不必担心引用它们。

如果是';重要的是";漂亮";名称显示在报告输出中,然后您可能想要使用它们。但是,您也可以使用列别名在表中使用小写名称,并且在查询的输出中仍然可以获得漂亮的名称:选择character_name as";字符名";来自福。

使用闭合区间比较:结果中包括指定范围两端的值。

这将包括时间戳正好为2018-06-08 00:00:00.000000的结果,但不包括当天晚些时候的时间戳。因此,这个查询似乎是可行的,但一旦你在午夜得到一个条目,你';我最终会重复计算。

对于整数或日期等离散量,只要记住结果中包含范围的两端,中间值是安全的。但它';这是一个坏习惯。

唐';t使用timestamp类型来存储时间戳,而使用timestamp tz(也称为带时区的时间戳)。

timestamptz记录了时间上的一个瞬间。不管名字怎么说,它都没有';t存储一个时间戳,只是一个时间点,用UTC表示,自2000年1月1日以来的微秒数。您可以在任何时区中插入值,它';我们将存储值描述的时间点。默认情况下,它将显示当前时区中的时间,但您可以使用at time zone在其他时区中显示时间。

因为它存储的是一个时间点,所以它将在涉及在不同时区输入的时间戳的算法上做正确的事情——包括夏时制时间变化不同侧面上相同位置的时间戳之间的时间戳。

时间戳(也称为无时区时间戳)不';它不会做任何事情,只会存储你给出的日期和时间。你可以把它想象成日历和时钟的画面,而不是时间点。如果没有额外的信息——时区——你不会';我不知道它记录了什么时间。因此,不同位置的时间戳之间或夏季和冬季的时间戳之间的算术可能给出错误的答案。

因此,如果你想存储的是一个时间点,而不是一个时钟的图片,请使用timestamptz。

如果你';以抽象的方式重新处理时间戳,或者只是从应用程序中保存和检索时间戳,而你不在';我不打算用它们做算术运算,那么时间戳可能是合适的。

不幸的是,在没有时区列的时间戳中存储UTC值通常是从缺乏可用时区支持的其他数据库继承的做法。

因为数据库无法知道UTC是列值的预期时区。

这使得许多其他有用的时间计算变得复杂。例如";在u.timezone#34给出的时区中的最后一个午夜;变成这样:

date#trunc(';day';,x.datecol在时区和#39;UTC和#39;在时区和#39;在时区和#39;UTC和#39;

带时区的time类型是由SQL标准定义的,但该定义显示出的属性导致其有用性受到质疑。在大多数情况下,日期、时间、不带时区的时间戳和带时区的时间戳的组合应提供任何应用程序所需的完整的日期/时间功能。

唐';对于时间戳列或时间戳强制转换,不要使用精度规格,尤其不要使用0。

因为它舍入了小数部分,而不是像大家所期望的那样截断它。这可能会导致意想不到的问题;当您将NOW()存储到这样的列中时,您可能会在将来存储一个半秒的值。

插入到char(n)字段中的任何字符串都将用空格填充到声明的宽度。那';这可能不是你真正想要的。

字符类型的值在物理上用空格填充到指定的宽度n,并以这种方式存储和显示。然而,在比较字符类型的两个值时,尾随空格在语义上是不重要的,并且被忽略。在空白比较重要的排序中,这种行为可能会产生意想不到的结果;例如选择';a';::字符(2)校对和#34;C"&书信电报;E';a\n';::Car(2)返回true,即使C语言环境会考虑一个空间大于一个换行符。将字符值转换为其他字符串类型时,会删除尾随空格。请注意,尾随空格在字符变化和文本值中具有重要的语义意义,在使用模式匹配时,尾随空格与正则表达式类似。

空间填充确实会浪费空间,但不会';不要让它的运行速度更快;事实上,情况正好相反,因为在许多情况下需要剥离空间。

它';需要注意的是,从存储角度来看,char(n)不是固定宽度的类型。实际字节数会有所不同,因为字符可能会占用多个字节,因此存储的值无论如何都会被视为可变长度(即使存储中包含空格填充)。

当你';重新移植使用固定宽度字段的非常非常旧的软件。或者当你读到上面手册中的片段并思考";是的,这很合理,很符合我的要求#34;而不是胡言乱语和逃跑。

有时人们对";唐';t使用char(n)和#34;与";但我的值必须始终精确到N个字符长#34;(例如,国家代码、哈希或来自其他系统的标识符)。即使在这些情况下,使用char(n)仍然是一个坏主意。

使用文本或文本上的域,带有CHECK(长度(值)=3)或CHECK(值';^[:alpha:][3}$';)或者类似的。

因为char(n)不';不要拒绝太短的值,它只是默默地用空格填充它们。因此';It’使用带有约束的文本来检查确切的长度没有实际的好处。作为奖励,这样的检查还可以验证值的格式是否正确。

记住,使用char(n)而不是varchar(n)对性能没有任何好处。事实恰恰相反。出现的一个特殊问题是,如果尝试将char(n)字段与驱动程序显式指定了文本或varchar类型的参数进行比较,可能会意外地无法使用索引进行比较。这可能很难调试,因为它没有';手动查询时不会出现。

唐';默认情况下,不要使用varchar(n)类型。考虑VARCHAR(没有长度限制)或文本替代。

varchar(n)是一个可变宽度的文本字段,如果尝试在其中插入长度超过n个字符(而不是字节)的字符串,则会引发错误。

varchar(不带(n))或text类似,但没有长度限制。如果在三个字段类型中插入相同的字符串,它们将占用完全相同的空间量,您将赢得';我无法衡量绩效上的任何差异。

如果你真正需要的是一个有长度限制的文本字段,那么varchar(n)就很好了,但是如果你选择任意长度并选择varchar(20)作为姓氏字段,你就';Hubert Blaine Wolfe-schlegel-stein-hausen-berger-dorff为您的服务注册时,您将面临生产错误的风险。

有些数据库没有';我没有一个可以容纳任意长文本的类型,或者如果他们这样做了';它不像varchar(n)那样方便、高效或得到很好的支持。当这些数据库的用户真正想要的是文本时,他们通常会使用varchar(255)之类的东西。

如果需要约束字段中的值,则可能需要比最大长度(也可能是最小长度,或有限的字符集)更具体的内容,而检查约束可以与最大字符串长度一起完成所有这些任务。

当你想的时候,真的。如果你想要的是一个文本字段,如果你在其中插入太长的字符串,它会抛出一个错误,而你没有';我不想使用显式检查约束,那么varchar(n)是一个非常好的类型。只是不要';不要不假思索地自动使用它。

此外,与文本类型不同,varchar类型在SQL标准中,因此它可能是编写超级可移植应用程序的最佳选择。

货币数据类型为';实际上,它不太适合储存货币价值。数字或(很少)整数可能更好。

它';它是一种定点类型,以机器int的形式实现,因此使用它的算法很快。但它没有';t处理零碎的一美分(或其他货币的等值),它';s的舍入行为可能不是你想要的。

它没有';t使用值存储货币,而不是假设所有货币列都包含数据库指定的货币';s lc_货币区域设置。如果出于任何原因更改lc_货币设置,所有货币列将包含错误的值。这意味着如果你插入'$10.00' 而lc#U货币设置为';恩!。UTF-8和#39;您检索到的值可能是';10,00列伊和#39;或';¥1,000' 如果信用证金额发生变化。

将值存储为数字(可能在相邻列中使用货币)可能更好。

如果你';我们只使用单一货币,不是吗;t处理分数美分,只做加法和减法,那么钱可能是正确的选择。

序列类型有一些奇怪的行为,使得模式、依赖关系和权限管理变得不必要的麻烦。

更一般地说,如果对多个表使用相同的序列,尽管在这些情况下,显式声明可能比串行类型更可取。

唐';不要在任何生产环境中通过任何TCP/IP方法(例如主机、主机SSL)使用信任身份验证。

它允许Internet上的任何人作为集群中的任何PostgreSQL用户进行身份验证,包括PostgreSQL超级用户。

您可以选择一系列身份验证方法,这些方法更适合于建立到PostgreSQL的远程连接。设置基于密码的身份验证方法相当容易,建议使用PostgreSQL 10及更高版本中提供的scram-sha-256。

信任身份验证仅适用于TCP/IP连接,前提是您信任pg_hba允许连接到服务器的每台计算机上的每个用户。指定信任的conf行。除了来自本地主机(127.0.0.1)的TCP/IP连接之外,对任何TCP/IP连接使用信任都是不合理的。

通过信任认证,任何用户都可以声称自己是任何其他用户,PostgreSQL将信任该断言。这意味着有人可以声称自己是postgres超级用户帐户,PostgreSQL将接受该声明并允许他们登录。

更进一步说,允许在生产环境中的本地UNIX套接字连接上使用信任身份验证也不是一个好主意,因为任何有权访问运行PostgreSQL的实例的人都可以作为任何用户登录。

较长的答案是,有几种情况下,信任验证可能是合适的:

作为可信网络上CI/CD作业的一部分,对PostgreSQL server运行测试

但你应该看看是否有其他方法更适合你。例如,在基于UNIX的系统上,可以使用对等身份验证连接到本地开发环境。