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 / 20132
Accepted
peter
peter
Asked: 2012-06-29 20:24:29 +0800 CST2012-06-29 20:24:29 +0800 CST 2012-06-29 20:24:29 +0800 CST

Resolvendo Problemas de Filtragem na Replicação de Mesclagem

  • 772

Estou no processo de definição de filtros em uma publicação de replicação de mesclagem para nosso banco de dados.

O problema que estou enfrentando é que a replicação de mesclagem tem essas regras, não gosto de chamá-las de limitações porque posso entender o propósito.

1) Ao criar um filtro de artigo, você não pode incluir uma subconsulta, ou pelo menos não deveria. Se fizer isso, parecerá funcionar na primeira vez que você sincronizar, mas se algo mudar na tabela de subconsulta, o filtro não será reavaliado.

2) Ao usar um filtro de junção, você só pode unir duas tabelas.

O problema que estou encontrando é que os relacionamentos em nosso banco de dados são mais complicados do que isso. Por exemplo, aqui está um de nossos relacionamentos,

user <- regions selected <- STREET LIGHTS -> settings (are we syncing street lights) -> user

Aqui está um exemplo de estrutura de tabela para explicar o que foi dito acima com mais detalhes,

Tabela de usuários,

Id    Username
1     petermc

UserRegion Table, (pense nisso como uma tabela de segurança, qual região um determinado usuário pode ver)

Id    UserId    RegionId
1     1         2
1     2         4

Tabela de configuração de sincronização,

Id    UserId    Table
1     1         StreetLight

Tabela de regiões (esta é apenas uma tabela de pesquisa para mostrar alguns exemplos de regiões)

Id    Region Name
1     North Auckland
2     South Auckland
3     Central Auckland
4     Great Barrier Island

Mesa Rodoviária,

Id    RegionId    Name
1     1           Rosedale Rd
2     1           North Shore Rd

Mesa Street Light

Id    RoadId    Last Replaced
1     1         2012-05-01
2     1         2009-06-03
3     2         2001-06-08

Portanto, neste caso, se eu escrevesse uma instrução select para aplicar minha filtragem para petermc, ficaria assim,

select * from StreetLight where
roadId in (select Id from Road where RegionId in (select regionId from UserRegion where userid = 1))
and exists (select 1 from syncsetting where userid = 1 and [table] = 'StreetLight')

Então eu estou fazendo duas coisas lá. Primeira filtragem com base na região para reduzir uma tabela muito grande em um subconjunto menor e mais gerenciável.

A segunda é especificar se o assinante está interessado na tabela StreetLight. Caso contrário, o assinante deve ter uma tabela StreetLight vazia. Esta parte é importante porque a publicação terá um grande número de tabelas nela, então não faz sentido incluir coisas que o assinante não vai usar.

Nosso maior banco de dados possui milhões de registros em algumas tabelas, e haverá uma quantidade moderada de atualizações desses registros também. Devemos obter esta filtragem correta. A opção de não filtrar essas tabelas não é viável.

sql-server merge-replication
  • 2 2 respostas
  • 2196 Views

2 respostas

  • Voted
  1. RBarryYoung
    2012-07-05T08:48:36+08:002012-07-05T08:48:36+08:00

    Esta é uma situação complicada, mas acho que a melhor solução seria criar uma tabela adicional (que chamarei de UserFilters), apenas para armazenar os dados consolidados das tabelas Road, UserRegion e SyncSetting em um único formato de linha combinado e em seguida, junte seu filtro de replicação a essa tabela. Essa tabela UserFilters precisaria ser mantida por gatilhos nas tabelas constituintes para que, quando as linhas em Road, UserRegion ou SyncSetting fossem alteradas, as linhas em UserFilters fossem alteradas automaticamente para corresponder. Vou demonstrar como fazer tudo isso abaixo.

    Primeiro uma nota; Esta tabela (UserFilters) é uma tabela desnormalizada que é adjunta ao seu esquema de dados de aplicativo normal. Ou seja, é um artefato operacional usado apenas para manipular a tecnologia de replicação para fazer o que você deseja e não faz parte do design/esquema de dados do seu aplicativo. Esse uso de desnormalização é considerado aceitável, pois é apenas para abordar limitações de tecnologia e não é usado diretamente por seus aplicativos.

    OK, aqui está como fazer isso:

    1. Escreva sua consulta de filtro desejada no formulário JOIN:

    Aqui está sua consulta de filtro original (desenrolada, para facilitar a decomposição):

    select  * 
    from    StreetLight 
    where   roadId in 
        (
        select  Id 
        from    Road 
        where   RegionId in 
            (
            select  regionId 
            from    UserRegion 
            where   userid = 1
            )
        )
      and   exists 
        (
        select  1 
        from    syncsetting 
        where   userid  = 1 
          and   [table] = 'StreetLight'
        )
    

    Queremos reescrever isso em um formato com apenas JOINs e WHEREs, mas sem subConsultas. (Isso sempre pode ser feito, mas não vou explicar como neste artigo.) Assim:

    SELECT  StreetLight.* 
    FROM    StreetLight 
    JOIN    Road        ON  Road.Id             = Streetlight.roadId
    JOIN    UserRegion  ON  UserRegion.regionid = Road.RegionId
    JOIN    syncsetting ON  syncsetting.userid  = UserRegion.userid
                        And syncsetting.[table] = 'StreetLight'
    Where   UserRegion.userid = 1
    

    2. Crie uma exibição consolidando todas as condições de filtro

    Usamos as cláusulas JOIN acima para fazer uma exibição que contém apenas as colunas relevantes para o filtro de replicação e que projeta todas as linhas necessárias para descrever completamente todas as condições do filtro. Isso é mais fácil do que parece, deve ficar assim:

    CREATE VIEW vwUserFilters As
    SELECT
            Road.Id             As RoadId,
            Road.RegionId       As RegionId,
            UserRegion.userid   As UserId,
            syncsetting.[table] As syncTable
    FROM    Road
    JOIN    UserRegion  ON  UserRegion.regionid = Road.RegionId
    JOIN    syncsetting ON  syncsetting.userid  = UserRegion.userid
    --  Comment the next line to generalize for all tables
    --                  And syncsetting.[table] = 'StreetLight'
    

    Observe que também generalizamos a expressão da View para abranger todos os usuários. Além disso, comentamos o SyncSetting "[table] = 'StreetLight'", a fim de generalizar isso para todas as tabelas cobertas por SyncSetting e Road (que podem ou não ser válidos, você terá que decidir isso).

    3. Crie a tabela UserFilters

    Crie a tabela UserFilters usando a exibição como guia para as colunas. No entanto, queremos adicionar uma coluna IDENTITY por motivos de desempenho de chave/índice:

    CREATE TABLE adjUserFilters 
    (
        filterId    INT Identity(1,1) PRIMARY KEY,
        RoadId      INT         NOT NULL,
        RegionID    INT         NOT NULL,
        userid      INT         NOT NULL,
        syncTable   VARCHAR(32) NOT NULL
    )
    

    Em seguida, preencha-o usando a Visualização:

    INSERT INTO adjUserFilters 
    SELECT RoadId, RegionID, UserId, syncTable FROM vwUserFilters
    

    Por motivos de desempenho e bloqueio, você desejará muitos caminhos de índice. Não posso dizer com certeza quais deveriam ser, mas aqui está o que eu começaria:

    CREATE UNIQUE INDEX IX_adjUserFilters 
        ON dbo.adjUserFilters(userid, syncTable, RoadId)
    CREATE INDEX IX_adjUserFilters_1 
        ON dbo.adjUserFilters(RegionID, userid)
    CREATE NONCLUSTERED INDEX IX_adjUserFilters_2 
        ON dbo.adjUserFilters(RoadId, userid)
    

    4. Adicionar acionadores de manutenção às tabelas constituintes

    Você precisará adicionar gatilhos às tabelas Road, UserRegion e SyncSetting para manter o conteúdo de [adjUserFilters] sincronizado com essas tabelas quando elas forem modificadas. Eles devem ficar assim: Primeiro, a tabela Road:

    CREATE TRIGGER dbo.trRoad_MaintainUserFilters_IUD 
       ON  dbo.Road
       AFTER INSERT,DELETE,UPDATE
    AS 
    BEGIN
        SET NOCOUNT ON;
    
        -- First, Remove any filter rows corresponding to any DELETE or UPDATE rows
        DELETE FROM adjUserFilters
        WHERE   RoadId IN(Select d.Id From deleted As d)
    
        -- Now, Add in any rows implied by any INSERT or UPDATE rows
        INSERT INTO adjUserFilters
        SELECT  v.RoadId, v.RegionID, v.UserId, v.syncTable 
        FROM    vwUserFilters As v
        JOIN    inserted      As i  ON i.Id = v.RoadId
    END
    

    A tabela UserRegion:

    CREATE TRIGGER dbo.trUserRegion_MaintainUserFilters_IUD 
       ON  dbo.UserRegion
       AFTER INSERT,DELETE,UPDATE
    AS 
    BEGIN
        SET NOCOUNT ON;
    
        -- First, Remove any filter rows corresponding to any DELETE or UPDATE rows
        DELETE FROM adjUserFilters
        WHERE   EXISTS(
            Select * From deleted As d 
            Where   d.UserId    = adjUserFilters.userid
              And   d.RegionId  = adjUserFilters.RegionId
            )
    
        -- Now, Add in any rows implied by any INSERT or UPDATE rows
        INSERT INTO adjUserFilters
        SELECT  v.RoadId, v.RegionID, v.UserId, v.syncTable 
        FROM    vwUserFilters As v
        JOIN    inserted      As i  
            ON  i.UserId    = v.userid
            And i.RegionId  = v.RegionId
    END
    

    E, finalmente, a tabela SyncSetting:

    CREATE TRIGGER dbo.trSyncsetting_MaintainUserFilters_IUD 
       ON  dbo.syncsetting
       AFTER INSERT,DELETE,UPDATE
    AS 
    BEGIN
        SET NOCOUNT ON;
    
        -- First, Remove any filter rows corresponding to any DELETE or UPDATE rows
        DELETE FROM adjUserFilters
        WHERE   EXISTS(
            Select * From deleted As d 
            Where   d.UserId    = adjUserFilters.userid
              And   d.[table]   = adjUserFilters.syncTable
            )
    
        -- Now, Add in any rows implied by any INSERT or UPDATE rows
        INSERT INTO adjUserFilters
        SELECT  v.RoadId, v.RegionID, v.UserId, v.syncTable 
        FROM    vwUserFilters As v
        JOIN    inserted      As i  
            ON  i.UserId    = v.userid
            And i.[table]   = v.syncTable
    END
    

    5. Crie sua consulta de filtro de replicação

    Agora você pode criar seu filtro de consulta de replicação para "user1" da seguinte forma:

    select  StreetLight.* 
    from    StreetLight     As t
    JOIN    adjUserFilters  As f  
        ON  f.syncTable = 'StreetLight'
        And f.RoadId    = t.RoadId
    Where   f.userid    = 1 
    -- (corrected)
    

    Conforme solicitado, este é o script que você usaria para sincronizar os adjUserFilters periodicamente, em vez de Triggers:

    DELETE FROM adjUserFilters;
    
    INSERT INTO adjUserFilters 
    SELECT RoadId, RegionID, UserId, syncTable FROM vwUserFilters
    

    De imediato, não tenho certeza de como você garantiria que isso fosse executado logo antes ou como parte do trabalho de sincronização de mesclagem, mas provavelmente pode ser feito.

    • 4
  2. Best Answer
    peter
    2012-12-18T12:34:22+08:002012-12-18T12:34:22+08:00

    Devo lançar um aviso. Agora nos afastamos da replicação de mesclagem e devo sugerir que o esquema acima pode ser um grande problema de desempenho.

    A exceção a isso exigiria que você tivesse uma pequena publicação com pequenas quantidades de filtragem e/ou filtros que não tivessem vários níveis de profundidade. Por exemplo, 10 a 100 artigos podem funcionar bem. Se você forçar demais o esquema acima, poderá ter problemas de desempenho/travamento.

    Toda vez que você insere um registro na tabela de filtragem superior, o gatilho de replicação de mesclagem deve processar todas as tabelas filhas. Ele também adiciona registros a MSMerge_contents e MSMerge_genhistory para todas as tabelas filhas. Quanto mais tabelas filhas você tiver, e se elas tiverem uma grande quantidade de registros nelas, mais poder de processamento será necessário.

    Tivemos um problema com sp_MSsetupbelongs sendo muito lento e expirando. No final, chegamos à conclusão de que estávamos pressionando demais a replicação de mesclagem e que essa tecnologia não funcionaria para nós.

    Isso me leva a sugerir que, se o esquema de filtragem na replicação de mesclagem pronta para uso não for flexível o suficiente para sua situação, não filtre ou não use a replicação de mesclagem. Teste Teste Teste embora, é claro, cada situação seja diferente.

    • 1

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

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 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

    Como selecionar a primeira linha de cada grupo?

    • 6 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +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