0

所以我有一张桌子:

CREATE TABLE TABLE_NAME (
    COLUMN_1   char(12)    NOT NULL,
    COLUMN_2   char(2)     NOT NULL,
    COLUMN_3   char(1)     NOT NULL,
    COLUMN_4   int         NOT NULL,
    COLUMN_5   char(2)     NOT NULL,
    COLUMN_6   money       NOT NULL,
    COLUMN_7   smallint    NOT NULL,
    COLUMN_8   varchar(10) NOT NULL,
    COLUMN_9   smallint    NOT NULL,
    COLUMN_10  datetime    NOT NULL
    Primary Key (COLUMN_1, COLUMN_2, COLUMN_3)
)

SELECT COUNT(*)返回与 不同的值SELECT DISTINCT COUNT(*)。这怎么可能?

我也试过

SELECT COUNT(*) FROM (
    SELECT
        COLUMN_1,
        COLUMN_2,
        COLUMN_3,
        COLUMN_4,
        COLUMN_5,
        COLUMN_6,
        COLUMN_7,
        COLUMN_8,
        COLUMN_9,
        COLUMN_10
     FROM TABLE_NAME
    ) TMP

它返回与不同查询相同的计数。

我看不到主键和所有字段都不是 NULL 的情况下,总计数可能与唯一记录的计数不同。

顺便说一句,这是在 Sybase ASE 15 上。

差异是 50 万条记录中的大约 100 条记录。我在其他几个表中也看到了这个问题,但只选择了一个作为示例。

编辑

为了完整起见,我应该提到我在编写一个简单的作业以将该表完全复制到远程数据库时发现了这个问题。我的应用程序正在记录一定数量的读/写操作,但由于源数据库中的记录数与目标数据库中的记录数不同,导致 QA 失败。这两个值都是通过COUNT(*);获得的。从目标(Oracle 10g)返回的计数与我的应用记录的读/写操作数相同。由于源表上的所有字段都定义为 NOT NULL 并且定义了主键,因此我无法解释我的应用程序如何丢失少量记录。

这是我开始使用上面列出的备用查询的时候,这两个查询都与我的应用程序读/写计数以及COUNT(*)从目标返回的值一致。换句话说,唯一不匹配的值是COUNT(*)源数据库上的 。

4

3 回答 3

6

在大多数支持它的数据库中,count(*)实际上并不检索所有记录并对其进行计数——而是获取一些元数据字段,该字段仅跟踪当前存储在表中的行数(或近似行数)。另一方面,当你做一些需要处理实际数据的事情时,dbms 无论如何都会获取这些行,它会按照你的预期计算它们。

当然,可以合理地预期,无论它是如何实现的,结果都count(*)将与更复杂但等效的查询相同。那将表明,(可能)您的表的元数据以某种方式损坏。(我会说这是一个不错的选择——我对 sybase 并不特别熟悉,但大多数 dbms 都有办法强制重建表指标……这可能值得一试)。

另一种可能的解释是,数据库的内部表行计数器实际上并未设计为 100% 准确。(这第二种可能性纯粹是有根据的推测......我实际上不知道这是否适用于 Sybase 的行计数器,但可能值得进一步调查)。

祝你好运!

于 2010-12-02T05:08:36.557 回答
1

如果我没记错的话,从这个来看:

你应该使用select count(distinct *). 我希望select distinct count(*)总是返回 1,因为它说“给我不同的行,每一行都是一个count(*)”,所以总是会有一行,同时select count(distinct *)给你不同行的计数。

FWIW,以上似乎适用于 v12.5(尽管我没有看到任何差异),这里是 15.0 文档:

它明确说明了以下内容:

count(*) 查找行数。count(*) 不接受任何参数,并且不能与 distinct 一起使用。无论是否存在空值,都会计算所有行。

您可以使用select count(distinct column_1)orso,但不能使用select count(distinct *).

于 2010-12-02T03:53:50.617 回答
1

这是 Sybase ASE 问题的 Sybase ASE 答案

它适用于任何符合标准 SQL 的 DBMS;它不适用于其他人。

您选择的答案不正确。

  1. COUNT()是 ISO/IEC/ANSI 标准 SQL 表达式。需要对行进行物理计数,这意味着它在大表上会很慢。要求使用内部存储器常驻表或目录表(“元数据”)。这是一个运行时值,因此如果表处于活动状态,它将在每次执行时不断变化
  • 您放在括号内的内容非常重要。

  • COUNT(*)返回包含空值的行数

  • COUNT(column)column返回Not Null的行数

  • 是的,位置DISTINCT也很重要。这迫使使用工作台。如果您需要计算不是唯一的列,那么您别无选择;但对于独特的列,没有必要使用DISTINCT

  • DISTINCT适用于列或从列派生的表达式;
    COUNT (DISTINCT *)
    是没有意义的(“区分所有列”),并且 ASE 15 有一个大大改进的解析器,它可以捕获这些东西(以前的版本会返回一个不太准确的错误消息)。

  • 实际读取的行数取决于您的 ISOLATION LEVEL(将返回指定级别的正确计数)和数据库上的当前活动

  • 避免你得到奇怪结果的最干净的方法是使用
    COUNT(PK_column)

  • (因为这是一个 CW)永远不要使用任何形式COUNT()的存在检查,因为它会物理计算行数。始终IF EXISTS与正确的WHERE子句一起使用,因为它只会使用索引。

  1. 如果您需要准确的计数但又不想读取所有行,则有一个读取目录表的函数,该函数对systabstats每个表中的行数进行计数。无论表大小如何,这都会立即返回。这些值的货币取决于您的服务器如何配置性能、刷新、检查点等。 systabstats通过两个命令从内存驻留表更新:UPDATE STATISTICS 和“flush stats”。尝试这个:
    EXEC sp_flushstats
    SELECT ROW_COUNT (DB_ID(), OBJECT_ID("table_name") )

回应评论

本节与 Sybase 无关

  1. 我已经为您的问题和主题提供了清晰的解释,但没有解释为什么其他两个答案不正确,或者为什么您的第二个查询返回不可预测的结果。

  2. 这是Sybase ASE 15.0 参考/构建块手册COUNT()位于第 121 页。请注意,icyrock 错误地引用了它,而且你们俩都误解了它,当然是无意的。你的出发点是混乱,缺乏区分 re*DISTINCT,因此我试图给出一个明确的答案。

  3. 我将此作为社区 Wiki,因此我的答案是完整的主题,已标准化,因此它可以独立作为任何问题的完整答案COUNT()

  4. 回应评论,对于那些没有听说过的人来说,SQL 是一种标准语言,由 IBM 在 1970 年代发明和发展,并在 1980 年代被以下人士接受为标准:

  • 国际标准组织

  • 国际电工委员会(书籍格式)

  • 并稍后被美国国家标准协会复制(感谢 Digital Equipment Corp 的免费出版)。

  • 开源或免费软件“SQL”均不符合该标准。它们提供了标准的一些组件(语言结构、工具、命令)。在他们提供的那些中,他们很少提供标准要求(例如 ACID 事务处理;安全性等)。

  • 第二个区别是架构,以及作为真正语言的 SQL 实现(一致性,可从任何代码段调用)。没有上下文切换的单个真正的多线程进程无法与使用 Unix 进行所有“多线程”和上下文切换的数百个程序相比。

  • 因此,SAP/Sybase 和 DB2(关于标准的刚性)所做的事情,以及在较小程度上 MS(关于实施的“灵活”)所做的事情,因为 (a) 它们符合标准(不争论小的变化),并且 (b ) 他们拥有真正的服务器架构,距离世界上的 MySQL 和 PostgreSQL 仅数光年。结果是硬件要求是架构服务器的 100 倍。你得到你所付出的。

  • Oracle 有一个特殊的位置,因为它是商业的和通用的,但是它不兼容 SQL(在语言或 ACID 事务中,并且它扩展了定义)。此外,它没有架构,因此属于免费软件类别。

  • 然后是非标准或反标准类别。
    MySQL/MyISAMCOUNT()以一种专门违反标准的方式提供(这从 Lee 提供的MySQL Manual 链接中显而易见;适用于非事务性应用程序)。
    MySQL/InnoDB & BDBCOUNT()以符合标准的方式提供。

  • PostgreSQL 是最差的,尽管市场营销很激烈。除了不符合 SQL 之外,它没有 ACID Transactions 的概念,并且“SQL”没有作为一种语言实现(Codd 的十二条规则中的规则 4)。不幸的是,在每个主要版本中,由于它实现了一些 SQL 增量,您必须重新编写代码。

  • 所有标准 SQL 供应商都提供了大量的标准扩展

  1. NOT NULL不能立即信任表定义中的 ,因为在实现当前定义之前,表中很可能有空列。尽管如此,Sybase 和 DB2 将根据标准合规性的要求计算物理抛出。您可以用一系列计数来证明:SELECT COUNT(column_1) from table_name,然后比较计数。

  2. 是的,第二个查询将进一步使您感到困惑,因为当创建并填充内部表时,计数将是准确的。既然你带着期望创造了它,它就满足了你的期望。但这并不能证明原始表格的任何内容。

于 2010-12-13T04:46:22.113 回答