I have an audit table with millions of rows. I indexed it and can live with the performance of the queries, but now I notice that the inserts are not always quick.
Under load, on average every 10th insert takes 500ms, although it's a bit random and the lengthy inserts seem to come in clusters of 3 like this (1st col = millisecs):
Dur SQL
2 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
2 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
2 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
532 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
299 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
586 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
2 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
1 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
1 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
5 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
4 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
3 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
1 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
5 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
1 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
4 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
3 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
1 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
453 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
597 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
452 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
2 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
2 INSERT INTO modification (forecastId, userId, epochTime, description, auxText, auxDate) VALUES (?,?,?,?,?,?)
What could the problem be?
This is the sequel (sorry couldn't stop myself) to Need to improve performance query a table with millions of rows - SQL Server
This is the DDL:
CREATE TABLE [dbo].[modification] (
[id] [int] IDENTITY,
[userId] [int] NOT NULL,
[epochTime] [bigint] NOT NULL,
[forecastId] [int] NOT NULL,
[description] [char](12) NOT NULL,
[auxText] [text] NULL,
[auxDate] [date] NULL
);
ALTER TABLE [dbo].[modification] ADD CONSTRAINT PK_mod2 PRIMARY KEY(ID);
ALTER TABLE [dbo].[modification] WITH CHECK
ADD CONSTRAINT [FK_modification_forecastId] FOREIGN KEY([forecastId])
REFERENCES [dbo].[forecast] ([id]);
ALTER TABLE [dbo].[modification] WITH CHECK
ADD CONSTRAINT [FK_mod_userId] FOREIGN KEY([userId])
REFERENCES [dbo].[user] ([id]);
CREATE NONCLUSTERED INDEX IX_modification_last_save
ON [dbo].[modification] (userId, forecastId, description, epochTime);
And I have tried to reduce locking with the NO LOCK
clause on the queries:
SELECT name, epochTime, auxDate
FROM modification WITH (NOLOCK)
JOIN [user] ON [user].id = modification.userId
WHERE forecastId = ? AND description = ?
ORDER BY epochTime DESC
Update
I dropped the index above, and it made no difference to the timings.
I disabled the foreign keys, and the bottleneck disappeared. I then worked out it was just because of the forecastId foreign key constraint. It's indexed just like the userId FK.
The only difference is on the actual parent tables, where the forecast
table has an extra clause FILLFACTOR
in the index creation which user
doesn't have:
ALTER TABLE [dbo].[forecast] ADD CONSTRAINT [PK_forecast]
PRIMARY KEY CLUSTERED
(
[id] ASC
) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON,
FILLFACTOR = 95
) ON [PRIMARY]
Could that FILLFACTOR
be the problem?