【问题标题】:Optimize a query of an indexed table when searching for values in the indexed column that occur a lot搜索索引列中出现次数多的值时,优化索引表的查询
【发布时间】:2021-01-29 15:36:41
【问题描述】:

我有一个包含营销电子邮件事件的表格,其中一个事件可能是我们发送了电子邮件,然后收件人单击或打开了它。每次点击和打开都是一个事件。我们有 2 年的数据,大约 1.5 亿行。

我从每个收件人电子邮件地址派生电子邮件域,并且我最近在该域列上放置了一个索引。这显着提高了性能,现在我将域和地址都包含在过滤器中。耗时 10 分钟,不到 10 秒。

至少,对于大多数域来说都是如此。有 740 万个唯一的电子邮件地址,其中几乎一半是 GMAIL。如果我查询 gmail 地址,它会非常慢,甚至可能比没有索引还要慢。至少前 50 个最常见的域需要至少一分钟的时间进行基本查询。下一个最常见的域有 40 万个电子邮件地址。

其中大部分是我们所说的“免费邮件”域,我有一长串潜在的免费邮件和其他非私有域(除了 gmail 等常见的电子邮件提供商,它还包括用户注册的“一次性”域for)-- 这个列表超过 5000 个。

我有两个问题/目标。首先,只是想出一种方法来更快地查询 Gmail(我可以有选择地将其应用于其他最常见的域)。我有一些想法,这可能很糟糕,比如用电子邮件地址的第一个字母创建一个列并在上面创建一个索引。 (我不是 DBA,我之前从未在 SQL Server 上创建过索引,所以不要以为我已经想到了一些显而易见的事情。

第二个目标是更普遍地将其用于 freemail 域表中的任何内容。大多数人不需要它,但它确保任何策略都保持最新,因为该免费邮件表会以某些自动方式和手动添加域进行更新。

一个示例查询和目标。

目标:总结特定用户在一段时间内的电子邮件参与度

select contact_email, month_year, event_type, count(event_type) as events
from event_table
where email_domain = 'domain' and contact_email = 'email address'
group by contact_email, month_year, event_type

每个评论者,关于执行计划的信息,将 gmail 与不常见的东西进行对比。我可以看到它们不同,不知道如何解释。

Gmail

Uncommon domain

【问题讨论】:

  • 如果您要过滤电子邮件,只需在 email 上创建索引。
  • 你能明确查询的目标是什么吗?
  • @GordonLinoff 有这么多不同的电子邮件地址,这仍然有效吗?我不确定是否有一个实际的上限才能真正使索引有价值。
  • @Vernou 我将在帖子中编辑并给出一个示例查询,但没有一个特定的目标或查询,我会出于各种目的进行类似的查询(根据 where 条件)。
  • 就像@Kirjava 提到的,执行计划是搜索SQL 瓶颈时最重要的事情之一。如果没有执行计划,没有人能够认真地帮助您解决您的具体问题。

标签: sql sql-server indexing


【解决方案1】:

这里的问题似乎是索引搜索,它是 0%,这意味着它在一种情况下效率低,在另一种情况下没有使用。

1 - 执行

SET STATISTICS IO ON;

它将激活当前会话的统计信息。它不会持续存在,因此无需在最后将其更改为关闭。

2 - 执行您的请求并记下您在第二个 SQL 管理选项卡上看到的内容。主要是由于统计请求而出现的 IO 逻辑读取数。

3 - 如果其他进程不使用,则删除此表上的现有索引。

4 - 正如 SQL 管理中所建议的那样。您可以复制他们建议的代码(更改索引名称)

CREATE NON CLUSTERED INDEX DP_LIVE_INDEX 
ON RawContactEvent(contact_email, email_domain) 
INCLUDE (event_type)

5 - 再次执行您的请求并再次检查 IO。如果它减少了很多,你的要求会更好。 还要再次检查执行计划。索引查找应该在右侧并且接近 100%。

说明

为什么我要关注逻辑读取而不是执行时间?

逻辑读取类似于 SQL Server 在找到选择结果之前搜索的条目数。

通常需要搜索的次数越多(逻辑读取次数越多),请求的时间就越长。如果有大量的逻辑读取,则意味着您的索引没有很好地使用,因为索引将更容易定位结果。

为什么不使用执行时间?

与执行时间相反,如果请求遵循相同的执行计划(如果请求未更改,则通常是这种情况),特定请求的逻辑读取将相同。这意味着它是您请求性能的一个非常好的指标。

为什么更改索引这么少?

您的执行计划认为您当前的索引没有用。通过更改它以使其成为多列索引或包含列,这可能会更改执行计划以更好地使用它,甚至有时只是在以前不使用它时使用它。让您的请求更有效率。

【讨论】:

  • 我现在正在做一些之前/之后的测试,需要一些时间来运行其中的一些并创建索引。
  • 这有很大的不同。我在域和地址上创建了索引,但没有包含事件类型,因为我希望它更通用。我将接受作为答案,因为它解决了我提供的特定用例。当我只过滤电子邮件域时,它对我没有帮助。当这成为一个实际问题时,我将创建一个新帖子,并且我还学到了一些对实时查询统计数据也有帮助的东西
  • 我想我会在这里再添加一个问题,也就是说,我可以盲目地执行查询统计信息所建议的操作,但我认为如果我只是继续为每个组合创建索引,收益将会递减我可能会做的分组/过滤?
  • 确实,创建过多索引会降低性能。但是在您的情况下,即使只有域上的请求也可以使用两列上的索引。首先,您应该尝试通过将 email_domain 放在首位来更改此索引:ON RawContactEvent(email_domain, contact_email)。这可能会使您的两个请求都使用它,因为顺序与多个索引有关(但与包含的索引无关)。如果这不起作用,请尝试创建第二个索引并检查两个查询之前和之后的性能。
  • 谢谢,我会尝试其他的东西
猜你喜欢
  • 2015-08-19
  • 1970-01-01
  • 2014-05-20
  • 2023-03-04
  • 2011-12-31
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
  • 2012-08-05
相关资源
最近更新 更多