Elimina morbida: utilizzare il flag isdeleted o la tabella di falegnameria separata?
-
28-10-2019 - |
Domanda
Dovremmo usare un flag per eliminazioni morbide o una tabella di falegnameria separata? Quale è più efficiente? Il database è SQL Server.
Informazioni di base
Qualche tempo fa abbiamo fatto entrare un consulente DB e guardare il nostro schema di database. Quando eliminiamo un record, aggiorneremmo un flag isdelettato sulle tabelle appropriate. È stato suggerito che invece di usare una bandiera, memorizzare i record eliminati in una tabella separata e utilizzare un join in quanto sarebbe meglio. Ho messo questo suggerimento al test, ma almeno in superficie, il tavolo extra e il join sembrano essere più costosi di quanto usare una bandiera.
Test iniziali
Ho impostato questo test.
Due tabelle, esempio e esemplare eliminato. Ho aggiunto un indice non cluster sulla colonna ISDLET.
Ho fatto tre test, caricando un milione di record con i seguenti rapporti eliminati/non eliminati:
- Cancellato/non sieduto
- 50/50
- 10/90
- 1/99
Risultati - 50/50
Risultati - 10/90
Risultati - 1/99
Script di database, per riferimento, esempio, esemplare eliminato e indice per esempio.
CREATE TABLE [dbo].[Example](
[ID] [int] NOT NULL,
[Column1] [nvarchar](50) NULL,
[IsDeleted] [bit] NOT NULL,
CONSTRAINT [PK_Example] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Example] ADD CONSTRAINT [DF_Example_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
GO
CREATE TABLE [dbo].[DeletedExample](
[ID] [int] NOT NULL,
CONSTRAINT [PK_DeletedExample] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DeletedExample] WITH CHECK ADD CONSTRAINT [FK_DeletedExample_Example] FOREIGN KEY([ID])
REFERENCES [dbo].[Example] ([ID])
GO
ALTER TABLE [dbo].[DeletedExample] CHECK CONSTRAINT [FK_DeletedExample_Example]
GO
CREATE NONCLUSTERED INDEX [IX_IsDeleted] ON [dbo].[Example]
(
[IsDeleted] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Soluzione
I numeri che hai sembra indicarlo la mia impressione iniziale era corretto: se la tua query più comune rispetto a questo database è filtrare IsDeleted = 0
, quindi le prestazioni saranno migliori con una semplice flag di bit, soprattutto se si fa un uso saggio degli indici.
Se si interrogano spesso per i dati eliminati e non slittati separatamente, è possibile vedere un guadagno di prestazioni avendo una tabella per oggetti eliminati e un altro per gli elementi non slittati, con campi identici. Ma denormalizzare i tuoi dati in questo modo è raramente una buona idea, poiché il più spesso ti costerà molto più nei costi di manutenzione del codice di quanto non ti guadagnerà negli aumenti delle prestazioni.
Altri suggerimenti
Non sono l'esperto SQL, ma secondo me, tutto dipende dalla frequenza di utilizzo del database. Se il database è accessibile dall'ampio numero di utenti e deve essere efficiente, l'utilizzo di una tabella ispelata separata sarà buono. L'opzione migliore sarebbe l'utilizzo di una bandiera durante il tempo di produzione e come parte di Maintanace giornaliera/settimanale/mensile è possibile spostare tutti i record eliminati morbidi sulla tabella isdelata e cancellare la tabella di produzione dei record eliminati morbidi. La miscela di entrambe le opzioni sarà buona.