首页 文章

SELECT COUNT(*)如何与表中所有记录的计数不同?

提问于
浏览
0

所以我有一张 table :

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上 .

差异是一百个左右的记录 . 我也在其他几个表中看到了这个问题,但只选择了一个例子 .

编辑:

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

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

3 回答

  • 1

    在大多数支持它的数据库中, count(*) 实际上并不检索所有记录并对它们进行计数 - 而是取出一些元数据字段,它只跟踪当前存储在表中的行数(或大致行数) . 另一方面,当您执行需要使用实际数据的操作时,dbms仍将获取行,并且它将按照您的预期计算它们 .

    当然,它实现了's reasonable to expect that, regardless of how it', count(*) 的结果与更复杂但等效的查询相同 . 那就是说,那个(也许)你的表's metadata is corrupted somehow. (I'd说这个是个好赌注 - 我不熟悉sybase,但是大多数dbms有办法强制重建表指标......这可能是值得的试试这里) .

    另一种可能的解释是,数据库的内部表行计数器实际上并未设计为100%准确 . (第二种可能性是纯粹受过教育的猜测......我实际上并不知道Sybase的行计数器是否属实,但可能值得进一步调查) .

    祝好运!

  • 6

    这是Sybase ASE问题的Sybase ASE答案

    它适用于任何标准SQL兼容DBMS;它 does not 适用于他人 .

    你选择的答案是不正确的 .

    • COUNT() 是ISO / IEC / ANSI标准SQL表达式 . 它需要 physically count the rows ,这意味着它在大型表上会很慢 . 需要 not 使用内部驻留表或目录表("metadata") . 这是一个运行时值,因此如果表处于活动状态,它将在每次执行时不断更改

    • 您在括号内放置的内容非常重要 .

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

    • COUNT(column) 返回 column 不为空的行数

    • 是的, DISTINCT 的位置也很重要 . 这会强制使用工作台 . 如果您需要计算非唯一的列,那么您没有选择;但对于唯一列,不需要使用 DISTINCT

    • DISTINCT 适用于从列派生的列或表达式;
      COUNT (DISTINCT *)
      是没有意义的("distinct all columns"),ASE 15有一个实质上改进的解析器,它捕获这样的东西(以前的版本woul dhave返回一个不太准确的错误消息) .

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

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

    • (因为这是一个CW)从不使用任何形式的 COUNT() 进行存在检查,因为它会对行进行物理计数 . 始终使用 IF EXISTS 和正确的 WHERE 子句,因为它只使用索引 .

    • 如果您需要准确计数但不想读取所有行,则有一个函数可以读取目录表 systabstats ,该表在每个表中都有行数 . 无论表大小如何,都会立即返回 . 这些值的货币取决于服务器的性能,刷新,检查点等的配置方式 . 通过两个命令从内存驻留表更新 systabstats :UPDATE STATISTICS和"flush stats" . 试试这个:

    EXEC sp_flushstats
    SELECT ROW_COUNT (DB_ID(), OBJECT_ID("table_name") )
    

    对评论的回应

    此部分与Sybase无关

    • 我提供了一个干净的解释你的问题和主题,而没有解释为什么其他两个答案是不正确的,或者为什么你的第二个查询返回不可预测的结果 .

    • 这是Sybase ASE 15.0 Reference/Building Blocks ManualCOUNT() 在第121页 . 注意,icyrock错误引用了它,你们两个都误解了它,无意中当然 . 你的出发点是混乱,缺乏区分,因此我尝试了一个明确的答案 .

    • 我把它做成了一个社区维基,因此我的回答是完整的主题,标准化,以便它可以独立作为任何问题的完整答案 COUNT() .

    • 在回复评论时,对于那些没有听过的人(没有冒犯,但有很多免费软件SQL用户在这里寻求答案) . SQL是一种 Standard 语言,由IBM在20世纪80年代发明和发展,并被以下标准接受为标准:

    • International Standards Organisation

    • International Electrotechnical Commission(Book Format)

    • 并稍后由American National Standards Institute(由于旧的数字设备公司免费出版)复制 .

    S0000 None 的OpenSource或免费软件"SQL"符合 Standard . 它们提供了标准的一些组件(语言结构,设施,命令) . 在他们提供的那些中,他们很少提供标准 Requirement (例如交易处理,安全性) .

    • 因此,Sybase和DB2(刚性标准)做了什么,以及在较小程度上MS(“关于实现”的“灵活性”)和Oracle(扩展定义)的作用,因为它们是标准兼容的(没有争论的小变化),距离MySQL和世界上的PostGreSQLs还有几年的历史 .

    • 然后有 non-Standard 或反标准类别 .
      MySQL / MyISAM以特定方式 against 标准提供 COUNT() (这在Lee提供的MySQL Manual link中非常明显;对于非事务性应用程序很有用) .
      MySQL / InnoDB和BDB以符合标准的方式提供 COUNT() .

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

    • 免费软件具有 Value 的地方,它们提供了大量的扩展(主要是代替标准),以简化Web服务器上的编码 . 他们都是不同的 .
      .

    • 表定义中的 NOT NULL 无法立即受信任,因为在实现当前定义之前,表中可能已包含空列 . 尽管如此,根据标准合规性的要求,Sybase和DB2将根据实际情况对物理进行计数 . 您可以通过一系列计数来证明: SELECT COUNT(column_1) from table_name ;然后比较计数 .

    • 第二个查询会进一步混淆你,是的,因为当创建并填充内部表时,计数将是准确的 . 由于您创造了期望,它满足了您的期望 . 但这并没有证明原始表格的任何内容 .

  • 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) 左右,但不能使用 select count(distinct *) .

相关问题