Sql 这项执行计划是重新思考我的主键的动机吗
当我进入我目前(雇主)的公司时,设计了一个新的数据库模式,它将成为许多未来正在/将要创建的工具的基础。 以我有限的SQL知识,我认为这个表设计得相当好。 我唯一关心的是几乎每个表都有一个多部分主键。每个表至少有一个CustomerId和它自己的键。虽然这些确实是对某个记录的定义,但我觉得多个键(我们这里说的是四个键)效率非常低 今天,我在一个简单的重复查询中看到了一些难以想象的CPU使用情况,该查询连接两个表,从第一个表中选择一个字符串字段并将它们区分开来Sql 这项执行计划是重新思考我的主键的动机吗,sql,clustered-index,Sql,Clustered Index,当我进入我目前(雇主)的公司时,设计了一个新的数据库模式,它将成为许多未来正在/将要创建的工具的基础。 以我有限的SQL知识,我认为这个表设计得相当好。 我唯一关心的是几乎每个表都有一个多部分主键。每个表至少有一个CustomerId和它自己的键。虽然这些确实是对某个记录的定义,但我觉得多个键(我们这里说的是四个键)效率非常低 今天,我在一个简单的重复查询中看到了一些难以想象的CPU使用情况,该查询连接两个表,从第一个表中选择一个字符串字段并将它们区分开来 select distinct(f.F
select distinct(f.FIELDNAME) as fieldName
from foo f
inner join bar b
on f.id = b.fId
where b.cId = @id;
检查执行计划(我不是EP英雄)时,我注意到有三个主要的CPU点。不同的(如预期)和两个在索引上搜索。
我个人认为指数搜索应该非常快,但它们每个都占成本的18%。这正常吗?这是由于(四倍)聚集索引造成的吗
--更新--该查询用于创建Lucene索引。这是一个一次性处理,大约每周发生一次(我知道这听起来有矛盾)。据我所知,我无法在此处重复使用任何结果。请运行以下查询并发布其输出:
SELECT COUNT(*), COUNT(DISTINCT fieldname)
FROM foo
SELECT COUNT(*), COUNT(DISTINCT cId), COUNT(DISTINCT fId)
FROM bar
这将有助于估计哪些索引最适合您的需要
同时确保您具有以下索引:
foo (FIELDNAME)
bar (cId, fId)
并重写您的查询:
SELECT DISTINCT(fieldname)
FROM foo f
WHERE EXISTS (
SELECT 1
FROM bar b
WHERE b.fId = f.id
AND b.cId = @id
)
此查询应使用
f.FIELDNAME
上的索引来构建独特的列表,并使用栏上的索引来过滤不存在的值。您是否可以运行以下查询并发布其输出:
SELECT COUNT(*), COUNT(DISTINCT fieldname)
FROM foo
SELECT COUNT(*), COUNT(DISTINCT cId), COUNT(DISTINCT fId)
FROM bar
这将有助于估计哪些索引最适合您的需要
同时确保您具有以下索引:
foo (FIELDNAME)
bar (cId, fId)
并重写您的查询:
SELECT DISTINCT(fieldname)
FROM foo f
WHERE EXISTS (
SELECT 1
FROM bar b
WHERE b.fId = f.id
AND b.cId = @id
)
此查询应使用f.FIELDNAME
上的索引来构建DISTINCT
列表,并使用bar
上的索引来过滤不存在的值。这种查询看起来很熟悉。我在这里猜测,但是,它可能是在web/winform ui上填充一个组合框,而这个组合框受到了相当大的冲击
也许您应该在应用程序端缓存结果,这样就不会经常执行它。更糟糕的情况是,您可以将其缓存在sql Server端,但这是一个巨大的难题 这种查询看起来很熟悉。我在这里猜测,但是,它可能是在web/winform ui上填充一个组合框,而这个组合框受到了相当大的冲击
也许您应该在应用程序端缓存结果,这样就不会经常执行它。更糟糕的情况是,您可以将其缓存在sql Server端,但这是一个巨大的难题 在大多数数据库中,如果索引中的第一列未列出,则不使用索引。您说customerId是每个主键的一部分,但在查询中不将其用于联接。为了正确回答您的问题,我们确实需要查看foo和bar的create table
输出,或者至少查看show index from
也就是说,如果您这样更改查询,您的查询可能会更快:
select distinct(f.FIELDNAME) as fieldName
from foo f
inner join bar b
on f.id = b.fId
and f.cId = b.cId #Using this part of the key will speed it up
where b.cId = @id;
我的评论假设您的主键有效地按“cId,fId”排序,这意味着您的查询不必检查每个cId,只检查索引中的cId。在大多数数据库中,如果索引中的第一列未列出,则不使用索引。您说customerId是每个主键的一部分,但在查询中不将其用于联接。为了正确回答您的问题,我们确实需要查看foo和bar的create table
输出,或者至少查看show index from
也就是说,如果您这样更改查询,您的查询可能会更快:
select distinct(f.FIELDNAME) as fieldName
from foo f
inner join bar b
on f.id = b.fId
and f.cId = b.cId #Using this part of the key will speed it up
where b.cId = @id;
我的评论假设您的主键被有效地排序为“cId,fId”,这意味着您的查询不必检查每个cId,只有那些是索引的一部分。最大的问题是,查询是否需要优化,或者应用程序是否需要在调用查询时少一点攻击性。两者兼而有之是没有坏处的:)你说少一点攻击性是什么意思?我正在做的是建立一个Lucene索引,用于快速搜索。这个查询需要对我拥有的每个@id重复,我看不到任何重复使用以前结果的方法。@boris,宾果,提前获取所有id,将它们插入临时表或其他内容,并将整个kaboodle作为一个集合选择。试着一次用一个id而不是一个id来做事情谢谢你的建议,我会在当前处理完成后立即运行查询。同时,你不认为聚集索引是这里的问题吗?最大的问题是,查询是否需要优化,或者应用程序是否需要在调用查询时少一点攻击性。这两种方法都可以做到:你是说少一点攻击性?我正在做的是建立一个Lucene索引,用于快速搜索。这个查询需要对我拥有的每个@id重复,我看不到任何重复使用以前结果的方法。@boris,宾果,提前获取所有id,将它们插入临时表或其他内容,并将整个kaboodle作为一个集合选择。试着一次用一个id而不是一个id来做事情谢谢你的建议,我会在当前处理完成后立即运行查询。同时,你不认为聚集索引是这里的问题吗?是的,我明白你的意思,但我觉得在我目前的情况下不是这样。请参阅OP了解最新情况。是的,我明白你的意思,但我觉得在我目前的情况下并非如此。请参阅OP以获取更新。CustomerId尚未使用,但将在将来使用。但我觉得它应该是常规字段的一部分,应该使用一个人工键。CustomerId还没有使用,但将来会使用。但我觉得它应该是规则域的一部分,应该有一个人工键