在非聚集索引中添加所有主键约束

如何解决在非聚集索引中添加所有主键约束

我用以下几列创建了一个表。所有列都是唯一键(列),我的表中没有主键。

Product

Bat_Key,product_no,value,pgm_name,status,industry,created_by,created_date

我已经更改了表格以添加约束

ALTER TABLE [dbo].[Product] 
    ADD CONSTRAINT [PRODUCT_PK] 
        PRIMARY KEY NONCLUSTERED ([Bat_Key] ASC,[product_no] ASC,[value] ASC,[pgm_name] ASC,)
                    WITH (STATISTICS_norECOmpuTE = OFF,IGnorE_DUP_KEY = OFF,ONLINE = OFF) ON [PRIMARY]
GO

如果我创建的索引如下:

CREATE NONCLUSTERED INDEX [PRODUCT_BKEY_PNO_IDX] 
ON [dbo].[PRODUCT] ([Bat_Key] ASC,[value],[pgm_name])
INCLUDE ([status],[industry]) 
         WITH (STATISTICS_norECOmpuTE = OFF,DROP_EXISTING = OFF,ONLINE = OFF) ON [PRIMARY]
GO

此设计是否适合以下选择查询

select * 
from Product 
where Bat_Key = ? and product_no=? 
order by product_no,pgm_name;

select * 
from Product 
where Bat_Key = ? and product_no=? and pgm_name = ? and value = ?

select * 
from Product 
where Bat_Key = ? and product_no=?

delete from Product 
where Bat_Key = ? and product_no=?

还是应该根据我的where子句创建不同的索引?

解决方法

聚集索引与非聚集索引有很大不同。实际上,两个索引的类型都包含根据您指定的列排序的数据。但是,

  • 聚集索引还包含表中的其余数据(nvarchar(max)之类的一些东西除外)。您可以考虑将其保存在数据库中
  • 非聚集索引仅包含您包含在索引中的列

如果没有聚集索引,则有一个“堆”。它们具有内置的行标识符,而不是PK。

在您的情况下,由于您的主键是非集群,因此用相同的字段创建另一个索引是没有意义的。要读取数据,它必须从PK中获取行标识符,然后再从堆中读取数据。

另一方面,如果您的主键是集群的(默认设置),则在某些情况下在字段上使用非集群索引可能会很有用。但是请注意,您添加的每个非聚集索引也会减慢更新,插入和删除的速度(因为还必须维护索引)。

在您的示例中-假设您在该字段中有一个字段,该字段在包含很多信息的行上是varchar(8000)。为了甚至从聚集索引中读取一行,它必须从其他字段读取(例如)100个字节,并从该新字段读取多达8000个字节。换句话说,它将您需要读取的数量乘以80倍。

我倾向于查看具有两种数据类型的表

  • 您汇总的数据
  • 您仅需逐行关注的数据

例如,在交易表中,您可能具有transaction_id,transaction_date,transaction_amount,transaction_description,transaction_entered_by_user_id。

  • 在大多数情况下,无论何时获得总计等,查看总计时您都经常需要交易金额和日期(例如,本周的交易总额是多少?)
  • 另一方面,description和user_id仅在您引用特定行时使用(例如,谁执行了此特定交易?)
  • 在这些情况下,即使它们与聚集索引重叠,我也经常在聚集中使用的字段上放置非聚集索引。它只是减少了所需的读取次数。

关于这一点的一个非常好的视频是布伦特·奥扎尔(Brent Ozar)称为How to think like the SQL Server Engine的视频-我强烈推荐它,因为它对我如何使用索引很有帮助。


关于您的特定示例-在索引中有两件事需要寻找:

  1. “探寻”数据集中特定点的能力(基于索引的种类)。
  2. 减少阅读量的能力。

就允许搜索而言,您需要以最适当的方式对索引进行排序。在进行过滤时(例如WHERE子句,JOIN),经验法则是首先查找“精确”匹配项。对于这些匹配项,只要它们全都匹配就无所谓到那点。

就您而言,您有

where Bat_Key = ? and product_no=? 
where Bat_Key = ? and product_no=? and pgm_name = ? and value = ?

这建议您的前两个字段应为Bat_Key和product_no(以任意顺序)。然后,您还可以具有pgm_name和value(也可以采用两种顺序)。

您也有

where Bat_Key = ? and product_no=? 
order by product_no,pgm_name;

对我来说,第三个字段应该是pgm_name(作为Bat_Key,product_no和pgm_name的索引将在其中提供您所需的内容)。

但是-这是一个很大的问题-您在其中有很多*,例如

select * 
from Product 
where Bat_Key = ? and product_no=?

因为选择的是*,所以不是聚簇索引的任何索引也需要返回到实际行,以获取*中包含的其余内容。

由于它们需要表中的所有字段(而不仅仅是索引中的字段),因此需要返回到堆(在您的情况下)。如果您在上面的字段上有一个聚集索引以及一个非聚集索引,则无论如何都必须从聚集索引中读取,因为其中存在查询所需要的信息。

再一次-上面的视频-解释得比我好得多。

因此,根据您的情况,我建议使用以下主键

ADD CONSTRAINT [PRODUCT_PK] 
        PRIMARY KEY CLUSTERED ([Bat_Key] ASC,[product_no] ASC,[pgm_name] ASC,[value] ASC)

差异

  • 它是群集的,而不是非群集的
  • 通过pgm_name重新排列了第3个字段和第4个字段的顺序
  • 由于没有太多其他内容需要阅读,因此不需要第二个非聚集索引。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?