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 / 96098
Accepted
Eric S
Eric S
Asked: 2015-03-25 09:09:35 +0800 CST2015-03-25 09:09:35 +0800 CST 2015-03-25 09:09:35 +0800 CST

Encontrando o final de uma cadeia de Relacionamento de forma otimizada

  • 772

Eu tenho uma tabela que contém uma coluna id, uma coluna pai e uma coluna filho. Então, para cada registro, eu sei qual registro vem antes dele e o que virá depois dele em um relacionamento em cadeia, mas do registro individual, não sei em que posição está dentro da cadeia nem qual é a primeira parte ou a última parte de a corrente.

Para fins de demonstração, suponha que temos a seguinte configuração. Percebo que há muitos problemas de design com esse tipo de configuração, mas é com isso que tenho que trabalhar.

CREATE TABLE Relationships (
ID VARCHAR(4), 
ParentID VARCHAR(4),
ChildID VARCHAR(4)
)

-- Insert root entries with their children
INSERT INTO Relationships (ID, ParentID, ChildID)
VALUES ('0001', '', '0003'), ('0002', '', '0004')

-- Now add further entries for each relationship chain
INSERT INTO Relationships(ID, ParentID, ChildID)
VALUES('0003', '0001', '0005'), ('0005', '0003', '0006'), ('0006', '0005', '0007'), ('0007', '0006', ''), 
  ('0004', '0002', '')

--Now we have two chains of 0001 -> 0003 -> 0005 -> 0006 -> 0007 and 0002 ->   0004

Com um CTE recursivo como abaixo, posso descobrir como todos os registros estão relacionados em sua cadeia e sua posição dentro da cadeia.

WITH RelationshipChain AS (
SELECT ID, ParentID, ChildID, 0 AS Seq, ID AS RootID
FROM Relationships WHERE ParentID = ''
UNION ALL
SELECT r2.ID, r2.ParentID, r2.ChildID, rc.Seq + 1 AS Seq, rc.RootID AS RootID
FROM Relationships r2 
INNER JOIN RelationshipChain rc ON rc.ChildID = r2.ID 
)

SELECT * FROM RelationshipChain
ORDER BY RootID, Seq

Para cerca de 2 milhões de registros, isso é executado em cerca de 30 segundos, o que é muito bom; no entanto, se eu tentar incluir também a parte final da cadeia, levará 4 vezes mais tempo para ser executado. Atualmente, estou fazendo assim:

WITH RelationshipChain AS (
SELECT ID, ParentID, ChildID, 0 AS Seq, ID AS RootID
FROM Relationships WHERE ParentID = ''
UNION ALL
SELECT r2.ID, r2.ParentID, r2.ChildID, rc.Seq + 1 AS Seq, rc.RootID AS RootID
FROM Relationships r2 
INNER JOIN RelationshipChain rc ON rc.ChildID = r2.ID 
)

SELECT * 
FROM RelationshipChain rc
CROSS APPLY (
SELECT MAX(Seq) AS FinalSeq FROM RelationshipChain WHERE rc.RootID = RootID
) AS b
CROSS APPLY (
SELECT ID AS LastChild FROM RelationshipChain WHERE b.FinalSeq = seq AND rc.RootID = RootID
) AS c
ORDER BY RootID, Seq

Existe uma maneira de fazer isso de forma mais eficiente?

sql-server performance
  • 1 1 respostas
  • 2030 Views

1 respostas

  • Voted
  1. Best Answer
    AakashM
    2015-03-26T01:06:17+08:002015-03-26T01:06:17+08:00

    Não tenho seu conjunto de dados, então não posso testar se isso é melhor, mas parece melhor. Depois de construir as cadeias, nós as invertemos para encontrar o item 'mais filho' em cada cadeia e, em seguida, juntamos de volta à cadeia original.

    -- The same as your first CTE
    ;WITH RelationshipChain AS (
    SELECT ID, ParentID, ChildID, 0 AS Seq, ID AS RootID
    FROM Relationships WHERE ParentID = ''
    UNION ALL
    SELECT r2.ID, r2.ParentID, r2.ChildID, rc.Seq + 1 AS Seq, rc.RootID AS RootID
    FROM Relationships r2 
    INNER JOIN RelationshipChain rc ON rc.ChildID = r2.ID 
    )
    
    -- This CTE is new and reverses the sense of the chains
    , BackChain AS (
    SELECT ID, RootID, ROW_NUMBER() OVER (PARTITION BY RootID ORDER BY Seq DESC) BackSeq
    FROM RelationshipChain
    )
    
    -- Now we join each chain to the childest item in the reverse chain
    SELECT 
        rc.ID
        , rc.ParentID
        , rc.ChildID
        , rc.Seq
        , rc.RootID
        , bc.ID ChainEndID
    FROM RelationshipChain rc INNER JOIN BackChain bc ON RC.RootID = bc.RootID AND bc.BackSeq = 1
    ORDER BY RootID, Seq
    

    Resultados com seus dados de amostra:

    ID   ParentID ChildID Seq         RootID ChainEndID
    ---- -------- ------- ----------- ------ ----------
    0001          0003    0           0001   0007
    0003 0001     0005    1           0001   0007
    0005 0003     0006    2           0001   0007
    0006 0005     0007    3           0001   0007
    0007 0006             4           0001   0007
    0002          0004    0           0002   0004
    0004 0002             1           0002   0004
    

    Os índices ajudarão no desempenho.

    • 2

relate perguntas

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

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

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

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