In regards to this specific query :
Don't expect to understand the data that is queried : it is irrelevant.
Just take a look at the WHERE clause :
SELECT
de.DocumentEntryId,
de.Number,
currentdev.ToIgnore,
previousdev.ToIgnore,
currentdev.DocumentEntryValueId AS CurrentDocumentEntryValueId,
SUM(currentper.Value) AS CurrentPaymentRate,
SUM(currentdevr.ConversionRate) AS CurrentConversionRate,
MAX(previousdev.DocumentEntryValueId) AS PreviousDocumentEntryValueId,
SUM(previousper.Value) AS PreviousPaymentRate,
SUM(previousdevr.ConversionRate) AS PreviousConversionRate
FROM
DocumentEntry de
INNER JOIN PaymentEntry currentpe ON currentpe.PaymentEntryId = de.CurrentPaymentEntryId
INNER JOIN DocumentEntryValue currentdev ON currentpe.DocumentEntryValueId = currentdev.DocumentEntryValueId
INNER JOIN DocumentEntryValue previousdev ON previousdev.DocumentEntryId = de.DocumentEntryId
INNER JOIN PaymentEntryRate currentper ON currentpe.PaymentEntryId = currentper.PaymentEntryId
INNER JOIN DocumentEntryValueRate currentdevr ON currentdev.DocumentEntryValueId = currentdevr.DocumentEntryValueId
INNER JOIN PaymentEntry previouspe ON previousdev.DocumentEntryValueId = previouspe.DocumentEntryValueId
INNER JOIN PaymentEntryRate previousper ON previouspe.PaymentEntryId = previousper.PaymentEntryId
INNER JOIN DocumentEntryValueRate previousdevr ON previousdevr.DocumentEntryValueId = previousdev.DocumentEntryValueId
WHERE
previousdev.DocumentEntryValueId <> currentdev.DocumentEntryValueId
AND currentdev.ToIgnore <> 1
AND previousdev.ToIgnore <> 1
AND currentpe.PaymentId = previouspe.PaymentId
GROUP BY
de.DocumentEntryId,
de.Number,
currentdev.ToIgnore,
previousdev.ToIgnore,
currentdev.DocumentEntryValueId
ORDER BY DocumentEntryId
Especially these two inequalities :
AND currentdev.ToIgnore <> 1
AND previousdev.ToIgnore <> 1
Note : ToIgnore is a bit column.
This query takes around 10 seconds to return about 1300 rows.
However, if I change these two lines to use the equality operator :
AND currentdev.ToIgnore = 0
AND previousdev.ToIgnore = 0
It takes forever to return anything.
It it helps, here are the indexes from each table :
Table DocumentEntry indexes :
ALTER TABLE [dbo].[DocumentEntry] ADD CONSTRAINT [DocumentEntry$0] PRIMARY KEY CLUSTERED
(
[DocumentEntryId] 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) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [IDX_DOCUMENTENTRY_REFNUMBER] ON [dbo].[DocumentEntry]
(
[EntryReferenceNumber] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_14227] ON [dbo].[DocumentEntry]
(
[MasterDocumentEntryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_186297_186296_DocumentEntry] ON [dbo].[DocumentEntry]
(
[Number] ASC
)
INCLUDE ( [DocumentEntryId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
Table DocumentEntryValue indexes :
ALTER TABLE [dbo].[DocumentEntryValue] ADD CONSTRAINT [DocumentEntryValue$0] PRIMARY KEY CLUSTERED
(
[DocumentEntryValueId] 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) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [IDX_DOCUMENTENTRYVALUE_DOCENTRYID] ON [dbo].[DocumentEntryValue]
(
[DocumentEntryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [IDX_DOCUMENTENTRYVALUE_REFNUMBER] ON [dbo].[DocumentEntryValue]
(
[EntryValueReferenceNumber] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_4022_4021_DocumentEntryValue] ON [dbo].[DocumentEntryValue]
(
[ReferenceDocumentId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
Table DocumentEntryValueRate indexes :
ALTER TABLE [dbo].[DocumentEntryValueRate] ADD CONSTRAINT [DocumentEntryValueRate$0] PRIMARY KEY CLUSTERED
(
[DocumentEntryValueRateId] 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) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_56865_56864_DocumentEntryValueRate] ON [dbo].[DocumentEntryValueRate]
(
[DocumentEntryValueId] ASC
)
INCLUDE ( [timestamp],
[DocumentEntryValueRateId],
[RateId],
[RateVersionId],
[RateTypeId],
[RateGroupId],
[RatePeriodValueId],
[ConversionRate]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
Table PaymentEntry indexes :
ALTER TABLE [dbo].[PaymentEntry] ADD CONSTRAINT [PaymentEntry$0] PRIMARY KEY CLUSTERED
(
[PaymentEntryId] 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) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [IDX_PAYMENTENTRY_DOCENTRYVALUEID] ON [dbo].[PaymentEntry]
(
[DocumentEntryValueId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_2517_2516_PaymentEntry] ON [dbo].[PaymentEntry]
(
[PaymentId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
Table PaymentEntryRate indexes :
ALTER TABLE [dbo].[PaymentEntryRate] ADD CONSTRAINT [PaymentEntryRate$0] PRIMARY KEY CLUSTERED
(
[PaymentEntryRateId] 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) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [IDX_PAYMENTENTRYRATE_PAYMENTENTRYID] ON [dbo].[PaymentEntryRate]
(
[PaymentEntryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_2618_2617_PaymentEntryRate] ON [dbo].[PaymentEntryRate]
(
[RateId] ASC
)
INCLUDE ( [timestamp],
[PaymentEntryRateId],
[PaymentEntryId],
[RateTypeId],
[RateGroupId],
[RateVersionId],
[RatePeriodValueId],
[Value]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
CREATE NONCLUSTERED INDEX [missing_index_2686_2685_PaymentEntryRate] ON [dbo].[PaymentEntryRate]
(
[RateTypeId] ASC,
[RateId] ASC,
[RatePeriodValueId] ASC
)
INCLUDE ( [PaymentEntryId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data Filegroup 1]
Here is a part of the estimated execution plan when I use the equality operators (= 0) :
Can someone explains why, in this case (or probably in many cases), the inequality operator seems faster than the equality operator ?