SQL Server - indexing a large table with multiple columns? or one index for every report?

3mpgtkmj  于 2023-06-28  发布在  SQL Server
关注(0)|答案(2)|浏览(133)

I have this table with millions of rows: Recording (Id, CampaignId, CallDateTime, Phone, etc)

And I have 2 different reports on that table:

--By Date:
declare @CampaignId int = 1, @Date date = '2023-06-27'
select * from Recording
where CampaignId = @CampaignId and cast(CallDateTime as date) = @Date

--By Phone:
declare @CampaignId int = 1, @Phone varchar(9) = '987654321'
select * from Recording
where CampaignId = @CampaignId and Phone = @Phone

It should have index, but how? With multiple columns (CampaignId, CallDateTime, Phone)? Or one index for every report (CampaignId, CallDateTime) and (CampaignId, Phone)?

Thanks.

wvt8vs2t

wvt8vs2t1#

First, you should fix the first query, or no index will be useful. It should be:

--By Date:
declare @CampaignId int = 1, @Date date = '2023-06-27'
select * from Recording
where CampaignId = @CampaignId 
and CallDateTime >= @Date
and CallDateTime < dateadd(day,1,@Date)

The general rule is never wrap the column in an expresson; always write the query so the parameter is instead. And check the Data Type Precedence to ensure that the column won't have to be converted to the parameter's type. Here Datetime is higher than Date, so no explicit conversion on the parameter is needed.

Next, start with the a single useful clustered index, perhaps (CampaignId,CallDateTime). This will give you an optimal plan for the first query and a reasonable plan for the second query.

If you have millions of rows and lots of different reporting queries that would require many different indexes for optimal performance, consider adding a non-clustered or clustered columnstore index . This switches to columnar storage with the highest compression and fastest scan rate. With a columnstore you don't need the perfect index for each reporting query because scanning a few million rows in a columnstore is really fast.

fafcakar

fafcakar2#

To create a good index for one query:

  • Start with column(s) tested with =
  • After that, you can add another column

where CampaignId = @CampaignId and CallDateTime >= @Date and CallDateTime < dateadd(day,1,@Date)

As David pointed out, making the tests Sargable is important. Then

(CampaignId, CallDateTime)   -- In this order

For this:

where CampaignId = @CampaignId and Phone = @Phone

have

(CampaignId, Phone)  -- The order is not important

Neither index is very useful for the other query. Make the optimal index for each query, then see if some indexes are the same or similar enough.

For example: INDEX(a,b,c) will work fine for a query that needs INDEX(a,b)

相关问题