AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 318188
Accepted
Rebecca
Rebecca
Asked: 2022-10-14 01:44:07 +0800 CST2022-10-14 01:44:07 +0800 CST 2022-10-14 01:44:07 +0800 CST

Por que meu ORDER BY em STRING_AGG nem sempre funciona?

  • 772
Esta pergunta foi migrada do Stack Overflow porque pode ser respondida no Database Administrators Stack Exchange. Migrado há 27 dias .

Eu tenho uma tabela que consiste em um ID de registro, um ID de grupo (vinculando 1 ou mais registros em um grupo) e um valor de hash para cada registro.

CREATE TABLE HashTable(
    RecordID VARCHAR(255),
    GroupIdentifier VARCHAR(255),
    Hash VARCHAR (255),
    GroupHashList VARCHAR(4000)
)

(Eu sei que esta não é uma tabela eficiente, mas é apenas uma tabela temporária para os propósitos deste exemplo).

Eu quero gerar um hash para cada grupo, então pensei que a maneira mais simples seria concatenar os hashes de cada registro do grupo. RecordIDs são exclusivos, mas o que esses registros se relacionam não são necessariamente exclusivos, portanto, os hashes podem ser duplicados. O objetivo disso é sinalizar grupos totalmente duplicados, ou seja, um grupo onde todos os registros desse grupo são duplicados de todos os registros de outro grupo. A GUI precisa que todos os membros do grupo tenham o mesmo hash para reconhecê-los como um grupo duplicado.

Estou usando STRING_AGG para concatenar os hashes individuais dos registros no grupo e classificá-los pelo hash para garantir que obtenha a mesma sequência de caracteres para grupos duplicados. Na verdade, não me importo com a ordem dos hashes, desde que seja sempre a mesma. Quando executo como uma consulta SELECT, funciona bem e posso ver strings idênticas para grupos duplicados. Quando eu pego essa mesma consulta SELECT e a coloco em uma consulta UPDATE, a ordenação parece se perder.

SELECT STRING_AGG([Hash],';') WITHIN GROUP (ORDER BY [Hash] ASC) 
FROM HashTable
GROUP BY [GroupIdentifier]

Isso fornece os resultados (para um exemplo de par de grupos duplicados):

73F294873462B2BA0E930FD16DCCB7;90E749375DF806CB6E3F5CA48FFA38;E44256CE7CFCB971EB679BAC25A697
73F294873462B2BA0E930FD16DCCB7;90E749375DF806CB6E3F5CA48FFA38;E44256CE7CFCB971EB679BAC25A697

Quando coloco esse mesmo código na consulta UPDATE, ele não os classifica corretamente:

UPDATE HashTable
SET GroupHashList = c.HashList
FROM HashTable
INNER JOIN (
    SELECT (STRING_AGG([Hash],';') WITHIN GROUP (ORDER BY [Hash] ASC)) AS [HashList],
        [GroupIdentifier]
    FROM HashTable
    GROUP BY [GroupIdentifier]) c
ON c.[GroupIdentifier] = HashTable.[GroupIdentifier]

Resultados para os mesmos dois grupos que são gravados na tabela:

73F294873462B2BA0E930FD16DCCB7;90E749375DF806CB6E3F5CA48FFA38;E44256CE7CFCB971EB679BAC25A697
73F294873462B2BA0E930FD16DCCB7;E44256CE7CFCB971EB679BAC25A697;90E749375DF806CB6E3F5CA48FFA38

o que estou perdendo?

O que estou recebendo pela primeira vez é

Hash1; Hash2; Hash3
Hash1; Hash2; Hash3

Mas quando está na consulta UPDATE, recebo

Hash1; Hash2; Hash3
Hash1; Hash3; Hash2

A consulta de atualização é classificada por ID de registro, embora eu não saiba se isso é coincidência. ( https://dbfiddle.uk/CPG1-z2l )

sql-server
  • 1 1 respostas
  • 1074 Views

1 respostas

  • Voted
  1. Best Answer
    Charlieface
    2022-10-14T08:02:27+08:002022-10-14T08:02:27+08:00

    Isso parece ser um bug no otimizador.

    O otimizador, tendo percebido que a junção é uma junção automática, está transformando-a em um agregado de janela. Ele pode fazer isso apesar STRING_AGGde não estar disponível como um agregado de janela. A regra é chamada GenGbApplySimple e permite que uma autojunção seja convertida em um agregado de janela. Não há nada especificamente errado com isso até agora.

    Plano

    PasteThePlan

    O problema é que a agregação está acima do valor errado. É agregar o valor externo ao invés do interno.

    Se você fornecer aliases diferentes às duas referências, um exame cuidadoso do plano de consulta revelará o bug.

    STRING_AGG([dbo].[HashTable].[Hash] as [HT1].[Hash],'')
    WITHIN GROUP (ORDER BY [HT2].[Hash])
    

    O outro problema é que os agregados usados ​​com essa regra (por exemplo MIN, MAX, , AVG) não têm uma WITHIN GROUPordenação para satisfazer, então o plano de substituição não leva em conta isso. Parece provável que STRING_AGGnão se destinava a funcionar as regras do GbApply , ou seria necessário trabalhar para torná-lo compatível (honrando a solicitação de classificação).

    Como você pode ver abaixo, o Ordenar somente ordena pela coluna de correlação GroupIdentifier, não pela Hashcoluna usada no arquivo WITHIN GROUP.

    <OrderBy>
      <OrderByColumn Ascending="1">
        <ColumnReference
          Database="[...]"
          Schema="[dbo]"
          Table="[HashTable]"
          Alias="[HT1]"
          Column="GroupIdentifier">
        </ColumnReference>
      </OrderByColumn>
    </OrderBy>
    

    Se você for um sysadmin, poderá desativar essa regra para a consulta usando o seguinte arquivo OPTION.

    OPTION (QUERYRULEOFF GenGbApplySimple)
    

    Como solução alternativa, uma opção para evitar que essa otimização seja aplicada é usar umOUTER APPLY

    UPDATE HT1
    SET GroupHashList = C.HashList
    OUTPUT inserted.*
    FROM HashTable AS HT1
    OUTER APPLY
    (
        SELECT
            HashList =
                STRING_AGG(HT2.[Hash], ';')
                    WITHIN GROUP (ORDER BY HT2.[Hash] ASC)
        FROM HashTable AS HT2
        WHERE HT2.GroupIdentifier = HT1.GroupIdentifier
    ) C;
    

    Isso oferece uma autojunção bastante simples com um Stream Aggregate .

    db<>violino


    Eu sugiro fortemente que você registre isso como um bug com a Microsoft.

    Você também pode deixar comentários , mas isso normalmente não leva a uma resposta específica.


    Como um aparte, você deve seguir as regras de alias sugeridas por Conor Cunningham ao escrever UPDATEinstruções de várias tabelas:

    A cláusula não-ANSI FROM (que você está usando aqui) tem comportamentos de ligação específicos que podem ou não ser o que você espera. Sugiro que você comece alias as 3 referências a hashtable para serem diferentes e, em seguida, verifique se está se referindo explicitamente à que deseja. Pode ser (estou supondo) que esteja vinculado a um diferente do que você pensa e forneça uma saída indesejada como resultado.

    • 22

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve