Meu cluster de banco de dados atualmente usa replicação lógica com wal_level definido como lógico. Como posso integrar a recuperação pontual (PITR) nesta configuração sem alterar o wal_level? Se for possível, também gostaria de saber quaisquer possíveis desvantagens dessa abordagem.
Tentando anexar um banco de dados (SQL 2016), com o seguinte comando:
CREATE DATABASE [MYDB]
ON (FILENAME = 'E:\DBA\Data\MYDB_Data.mdf')
FOR ATTACH;
Renderiza o seguinte erro:
Msg 5120, Level 16, State 101, Line 4
Unable to open the physical file "E:\DBA\Data\MYDB_Data.mdf". Operating system error 5: "5(Access is denied.)".
Msg 1802, Level 16, State 7, Line 4
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
Outros sugeriram que as permissões podem ser o problema. Não vejo isso no meu caso:
PS E:\DBA\Data> icacls .
. NT SERVICE\MSSQLSERVER:(F)
BUILTIN\Administrators:(F)
CREATOR OWNER:(OI)(CI)(IO)(F)
NT AUTHORITY\SYSTEM:(OI)(CI)(F)
BUILTIN\Administrators:(OI)(CI)(F)
NT SERVICE\MSSQLSERVER:(OI)(CI)(F)
Successfully processed 1 files; Failed processing 0 files
PS E:\DBA\Data> icacls .\MYDB_Data.mdf
.\MYDB_Data.mdf BUILTIN\Administrators:(F)
NT AUTHORITY\SYSTEM:(F)
NT SERVICE\MSSQLSERVER:(F)
Successfully processed 1 files; Failed processing 0 files
A conta de serviço é uma conta de domínio que está no grupo Administradores local. Existe alguma esperança para mim?
Estou usando o Postgres 12 e no meu aplicativo tenho uma tabela que estou usando para armazenar eventos específicos que contêm informações sobre coisas que aconteceram fora do sistema e relacionadas a alguns registros no meu BD. A tabela se parece com isso:
CREATE TABLE events (
id BIGSERIAL PRIMARY KEY,
eventable_type VARCHAR(255) NOT NULL,
eventable_id BIGINT NOT NULL,
type VARCHAR(255) NOT NULL,
data JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
);
CREATE INDEX index_events_on_eventable ON events (eventable_type, eventable_id);
Por exemplo: uma reunião foi agendada no Google Agenda. Um evento é criado nesta tabela com os detalhes do que aconteceu e o registro é associado à representação interna da reunião no BD. O data
atributo contém os detalhes do evento que também contêm um id exclusivo como:
INSERT INTO events (eventable_type, eventable_id, type, data) VALUES ('MyInternalEvent', 1234, 'GoogleCalendarEvent', '{"action": "created", "GoogleId": "abcdef1234"}'::jsonb);
INSERT INTO events (eventable_type, eventable_id, type, data) VALUES ('MyInternalEvent', 1234, 'GoogleCalendarEvent', '{"action": "updated", "GoogleId": "abcdef1234"}'::jsonb);
INSERT INTO events (eventable_type, eventable_id, type, data) VALUES ('MyInternalEvent', 1234, 'GoogleCalendarEvent', '{"action": "deleted", "GoogleId": "abcdef1234"}'::jsonb);
INSERT INTO events (eventable_type, eventable_id, type, data) VALUES ('MyInternalEvent', 5678, 'GoogleCalendarEvent', '{"action": "created", "GoogleId": "dsfsdf2343"}'::jsonb);
INSERT INTO events (eventable_type, eventable_id, type, data) VALUES ('MyInternalEvent', 5678, 'GoogleCalendarEvent', '{"action": "updated", "GoogleId": "dsfsdf2343"}'::jsonb);
INSERT INTO events (eventable_type, eventable_id, type, data) VALUES ('MyInternalEvent', 5678, 'GoogleCalendarEvent', '{"action": "deleted", "GoogleId": "dsfsdf2343"}'::jsonb);
Eu consulto a tabela de eventos assim:
SELECT * FROM events WHERE events.type = 'GoogleCalendarEvent' AND (data->>'GoogleId' = 'abcdef1234') LIMIT 1;
Em termos de cardinalidade de operações, o número de gravações é aproximadamente 3 vezes maior que o número de leituras . Ou seja: escrevemos mais do que lemos. A tabela tem cerca de 3 milhões de linhas, crescendo rapidamente. Cerca de 300 mil linhas são adicionadas à tabela todos os dias.
No momento, armazenamos apenas um outro type
evento na tabela, vamos chamá-lo de GoogleEmailEvent
. Filtrar por GoogleCalendarEvent
retornaria aproximadamente 50% dos registros na tabela. Filtrar por GoogleId
normalmente retornaria menos de 10 registros, mas realmente precisamos de apenas 1 porque todos eles estão associados ao mesmo "Eventable", como você pode ver nas inserções de exemplo.
Quero melhorar o tempo de execução da consulta, pensei em:
- adicionando um índice
WHERE data->>'GoogleId' IS NOT NULL
. Mas estou preocupado em deixar as gravações mais lentas - armazenando
data->>'GoogleId'
em uma tabela separada junto com o id do evento para permitir uma recuperação rápida. Quão eficaz isso seria? Isso também tornaria as gravações um pouco mais lentas. - indexando
created_at
e usando isso na consulta para restringir os registros na consulta de alguma forma
Detalhe importante: A grande maioria das vezes (99% das vezes ou mais) o evento correspondente é aquele que foi inserido na tabela recentemente (digamos, em 10 minutos). Posso aproveitar esses detalhes para acelerar a consulta? Adicionar resolveria ORDER BY Id DESC LIMIT 1
o problema?
Digamos que eu queira armazenar os dados fornecidos pelo usuário em uma tabela chamada post
.
- os dados dos usuários são isolados por
user_id
coluna select sum(likes_count) where user_id = $
deveria ser rápidoselect * from post where id = $
deveria ser rápido
Você poderia ajudar a comparar esses esquemas em termos de desempenho, indexação e casos de uso típicos?
nota: os valores char(24) são a string hexadecimal ObjectId do MongoDB. eles são exclusivos no banco de dados.
Esquema 1:
usando PRIMARY KEY (id)
e índice secundário em(user_id)
CREATE TABLE posts_v1 (
id CHAR(24) NOT NULL,
user_id CHAR(24) NOT NULL,
likes_count INT,
PRIMARY KEY (id),
KEY 'user_id_idx' (user_id)
);
usando PRIMARY KEY (user_id, id)
e índice exclusivo secundário em(id)
Esquema 2:
CREATE TABLE posts_v2 (
id CHAR(24) NOT NULL,
user_id CHAR(24) NOT NULL,
likes_count INT,
PRIMARY KEY (user_id, id),
UNIQUE KEY 'id_idx' (id)
);
Questões:
1- Em quais cenários um esquema teria desempenho melhor que o outro? Por exemplo, consultas que filtram por user_id, id ou ambos.
2- posts_v2
O esquema usa menos leituras de página do InnoDB ao consultar por user_id
? Presumo que, no caso de posts_v2
, a tabela esteja fisicamente agrupada por user_id
, para que possamos recuperar todas as postagens dos usuários com menos varreduras de página. Minha suposição é verdadeira?
3- Integridade e manutenção de dados: Há alguma implicação para integridade de dados, manutenção ou evolução futura de esquema com qualquer design?
4- Casos de uso: Quais são os casos de uso ou cargas de trabalho típicos que podem favorecer um design em detrimento de outro?
Agradeço quaisquer insights ou recomendações que você possa fornecer!
usando a estratégia de backup do Ola , há um trabalho
databaseBackup - bancos de dados do sistema cheios, como você pode ver na figura abaixo.
esse trabalho está programado para ser executado uma vez por semana, no domingo de manhã.
está tudo bem, já está funcionando há algum tempo.
Agora preciso alterá-lo para funcionar todos os dias.
isso funciona bem usando ssms, criando scripts para a mudança e aplicando-a.
porém, como preciso fazer isso em dezenas de servidores, precisarei de um script que descubra qual é o agendamento, altere-o e reaplique-o no trabalho
Não consegui, mas me pergunto se alguém já fez isso.
Tenho dois servidores SQL configurados com um grupo de disponibilidade. As configurações usam um dnn como ouvinte. Os testes de conexão com a porta configurada foram bem-sucedidos.
Quando tentamos fazer uma conexão com multisubnetfailover=true na string de conexão, recebemos a seguinte mensagem de erro:
Não há suporte para conexão com uma instância espelhada do SQL Server usando a propriedade de conexão multiSubnetFailover.
Este sistema nunca foi configurado com espelho. eu corri
SELECT * FROM SYS.DATABASE_MIRRORING
Os resultados do comando foram NULL. Alguma sugestão do que posso verificar para resolver isso?
Estou configurando um ambiente de teste/PreProd fazendo backups noturnos de nosso ambiente Prod e aplicando-os ao nosso novo ambiente PreProd. Esta parte está funcionando bem. Infelizmente, temos várias replicações configuradas em nosso ambiente. Eu configurei procs para remover a replicação PreProd logo antes das restaurações noturnas e, em seguida, recriá-la após a conclusão das restaurações. Isso funciona bem, mas leva muito tempo (3 a 4 horas), pois algumas mesas são bem grandes. Gostaria de compactar essas tabelas grandes, mas não quero dobrar o trabalho. A primeira etapa da aplicação do instantâneo é eliminar e recriar a tabela de destino. O segundo passo é inserir todos os dados. Eu poderia compactar logo depois disso, mas basicamente estou construindo a tabela duas vezes, a primeira vez descompactada e a segunda vez com compactação.
Testei o parâmetro @pre_snapshot_script, mas ele é aplicado antes da etapa que elimina e recria a tabela (os arquivos .pre e .sch na pasta Snapshot). Isso não funcionará.
Há alguma maneira de garantir programaticamente que a tabela de assinantes seja compactada ANTES de os dados do instantâneo serem aplicados a ela?
Cenário
Eu tenho uma tabela grande particionada em uma INT
coluna. Quando executo duas MERGE
instruções diferentes em duas partições diferentes desta tabela, elas parecem estar bloqueando uma à outra.
Exemplo de código para recriar o cenário:
1. Preparação. Crie tabelas e alguns dados fictícios
SET NOCOUNT ON
GO
--
-- Create parition function and partition scheme
--
DROP FUNCTION IF EXISTS PF_Site_ID
GO
CREATE PARTITION FUNCTION PF_Site_ID (INT)
AS RANGE RIGHT FOR VALUES (
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
)
GO
DROP PARTITION SCHEME PS_Site_ID
GO
CREATE PARTITION SCHEME PS_Site_ID
AS PARTITION PF_Site_ID
ALL TO ('PRIMARY')
GO
--
-- Large table partitioned on Site_ID. Two STG tables. And some dummy data
--
DROP TABLE IF EXISTS dbo.PartitionedLargeTable
GO
CREATE TABLE dbo.PartitionedLargeTable
(
ID INT NOT NULL IDENTITY(1,1)
, Site_ID INT NOT NULL
, Name VARCHAR(50)
) ON PS_Site_ID (Site_ID)
GO
ALTER TABLE dbo.PartitionedLargeTable SET (LOCK_ESCALATION = AUTO)
GO
--
-- STG tables
--
DROP TABLE IF EXISTS dbo.STG_Test1
GO
CREATE TABLE dbo.STG_Test1
(
ID INT NOT NULL IDENTITY(1,1)
, Site_ID INT NOT NULL
, Name VARCHAR(50)
) ON [PRIMARY]
GO
DROP TABLE IF EXISTS dbo.STG_Test2
GO
CREATE TABLE dbo.STG_Test2
(
ID INT NOT NULL IDENTITY(1,1)
, Site_ID INT NOT NULL
, Name VARCHAR(50)
) ON [PRIMARY]
GO
--
-- Dummy data
--
INSERT INTO dbo.PartitionedLargeTable (Site_ID, Name) SELECT 1, NEWID()
INSERT INTO dbo.PartitionedLargeTable (Site_ID, Name) SELECT 2, NEWID()
GO 10000
INSERT INTO dbo.PartitionedLargeTable (Site_ID, Name)
SELECT Site_ID, Name FROM dbo.PartitionedLargeTable
GO 5
INSERT INTO dbo.STG_Test1(Site_ID, Name) SELECT 1, NEWID()
GO 10000
INSERT INTO dbo.STG_Test2(Site_ID, Name) SELECT 2, NEWID()
GO 10000
INSERT INTO dbo.STG_Test1 (Site_ID, Name)
SELECT Site_ID, Name FROM dbo.STG_Test1
GO 7
INSERT INTO dbo.STG_Test2 (Site_ID, Name)
SELECT Site_ID, Name FROM dbo.STG_Test2
GO 7
2. MESCLAR 1
Em uma janela do SSMS, execute esta MERGE
instrução:
MERGE dbo.PartitionedLargeTable AS TGT
USING (SELECT ID, Site_ID, Name FROM dbo.STG_Test1) AS SRC
ON SRC.Site_ID = TGT.Site_ID
AND SRC.ID = TGT.ID
WHEN MATCHED THEN
UPDATE
SET TGT.Name = SRC.Name
WHEN NOT MATCHED THEN
INSERT (Site_ID, Name)
VALUES (SRC.Site_ID, SRC.Name);
3. MESCLAR 2
Em uma segunda janela do SSMS, execute esta MERGE
instrução:
MERGE dbo.PartitionedLargeTable AS TGT
USING (SELECT ID, Site_ID, Name FROM dbo.STG_Test2) AS SRC
ON SRC.Site_ID = TGT.Site_ID
AND SRC.ID = TGT.ID
WHEN MATCHED THEN
UPDATE
SET TGT.Name = SRC.Name
WHEN NOT MATCHED THEN
INSERT (Site_ID, Name)
VALUES (SRC.Site_ID, SRC.Name);
As duas MERGE
instruções são executadas em Site_IDs diferentes (portanto, duas partições diferentes).
Um dos benefícios de desempenho das tabelas particionadas é que podemos manipular partições independentemente umas das outras (dentro do razoável). Portanto, algo como INSERT
ou UPDATE
em uma partição não bloqueará operações semelhantes em outras partições.
Compare isso com quando a tabela NÃO está particionada, se realizarmos duas INSERT
operações grandes (ou duas UPDATE
operações grandes), então uma bloqueia a outra quando o número de linhas manipuladas ultrapassa um certo número (algo como 3k ou 5k linhas), então o PAGE
lock é escalado para TABLOCK
. Portanto, INSERT
blocos INSERT
(ou UPDATE
blocos UPDATE
)
Para evitar esse escalonamento de bloqueio para TABLOCK
, esta tabela foi particionada com LOCK_ESCALATION = AUTO, que limita os bloqueios até o nível HOBT (e não a tabela). Mas com MERGE
o bloqueio ainda acontece.
Alguma idéia de como evitar esse bloqueio? Temos 10 MERGE
instruções paralelas em execução, em 10 partições diferentes desta grande tabela (e elas estão bloqueando umas às outras).
A imagem abaixo mostra a natureza do bloqueio. Quando uma tabela é particionada, o escalonamento de bloqueio deve ir apenas até a partição (não até a tabela inteira). Quando essas MERGE
instruções estão em execução, vejo os IDs do HOBT que cada um MERGE
está consultando (bloqueando). E em alguns casos, o ID HOBT não corresponde aos IDs de partição desta tabela.
A tabela real com a qual trabalho possui um COLUMNSTORE CLUSTERED
índice no esquema de particionamento.
Estou usando o MySQL 5.7 e percebi algo que não consigo explicar para mim mesmo com meu conhecimento atual, então aqui vai.
Uma data "inválida" é 0000-00-00
considerada igual NULL
a um date
tipo de coluna sem possibilidades de valores anuláveis? Veja o exemplo a seguir:
create table if not exists example
(
id int auto_increment primary key,
doskip date default '0000-00-00' not null
);
INSERT INTO example VALUES(1, '0000-00-00'), (2, '0000-00-00'), (3, '0000-00-00');
Ter o que foi dito acima e executar as seguintes consultas me deu exatamente a mesma contagem: 3 e eu me pergunto por que, há alguma explicação para isso?
SELECT COUNT(*) FROM example j WHERE j.doskip = '0000-00-00';
SELECT COUNT(*) FROM example j WHERE j.doskip IS NULL;
Aqui está um Fiddle mostrando esse comportamento, é por causa do modo?