
[英]If I place a composite index on three columns and use them in the same query but in different places, will it still be effective?
[英]Composite index on three columns
我们得到了93M行的映射表,其中保存了三个表和对应的三个表的映射信息。 我们在从映射表访问数据时面临性能问题。
表名 | PK信息 | 行数 |
---|---|---|
卖方 | SellerId 主键 | 3000 行 |
店铺 | StoreId 主键 | 20000 行 |
产品 | ProductId 主键 | 200k 行 |
卖家商店产品映射 | SellerId,ProductId,StoreId 复合非聚集索引。 此表中还有一个代理键:SellerStoreProductMappingId,用作集群的主键 | 93M 行 |
我们的查询可以访问以下三种组合中的任何一种:93M 行表中的Seller, Product, Store
。
我的实际查询是这样的:
SELECT < many columns from four tables>
FROM SellerStoreProductMapping
INNER JOIN Store
INNER JOIN Seller
INNER JOIN Product ...
WHERE SellerId = 123
但是,正在发生的是非聚集索引:SellerId、ProductId、StoreId 在我们的查询中很少使用,即使我们对 SellerId 进行了过滤。 它用于 storeId 的索引扫描。
我们的疑问是,对于这三列组合,
注意:我们无法创建聚集列存储索引,因为我们将 ROWVERSION 数据类型作为映射表中的数据类型之一。
这可能不是答案(但我不允许发表评论),还有一点需要考虑:综合索引中的索引顺序。
如果您在 SellerStoreProductMapping 表中按以下顺序定义复合索引:SellerId,StoreId,ProductId,那么它只能有效地用于过滤 SellerID OR for (SellerId and StoreId) OR for (SellerId and StoreId and ProductId) 的查询
如果您在查询中将三列(7 种可能性)的所有可能组合作为过滤器,那么您可能需要定义至少三个单独的索引。
可以在此处找到对此的一些参考: https://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys
如果该索引涵盖了查询中的所有信息并且谓词是可搜索的,那么您的索引将被系统地使用。
例如,让我们看看这些查询:
--1
SELECT *
FROM SellerStoreProductMapping
WHERE Seller = 1 AND Product = 2 AND Store = 1
-- 2
SELECT Seller, Product, Store
FROM SellerStoreProductMapping
WHERE Seller = 1 AND Product = 2 AND Store = 1
-- 3
SELECT anyOtherColumns
FROM SellerStoreProductMapping
WHERE Seller = 1 AND Product = 2 AND Store = 1
-- 4
SELECT Seller, Product, Store
FROM SellerStoreProductMapping
WHERE Seller = 1 AND Product = 2 AND Store = 1
ORDER BY anyOtherColumns
只有查询 2 会系统地使用索引。 所有其他查询(1、3、4)没有查询中使用的所有列,在索引键中......所以他们必须使用双重读取:
两次读取的成本与扫描表等其他策略的成本相比。 如果扫描成本较低,则不会使用索引...
关于索引中的列顺序要记住的一些经验法则:
WHERE =
predicate 中引用的任何列以及唯一连接中引用的任何列放在索引键的第一个位置(连接从另一个表返回单行)> <= < <> BETWEEN
INCLUDE
因此,如果您的查询是针对单个卖家和商店,但有很多产品,那么您需要一个索引(Seller, Store, Product)
或(Store, Seller, Product)
,具体取决于列的选择性。
进一步说明:
如果您选择的列未包含在索引中,编译器可能会决定执行聚集索引扫描,因为额外的键查找成本可能不值得。
只有当编译器可以计算出连接在唯一的行上时,编译器才能检测到唯一的连接表。 因此,请始终确保使用PRIMARY/UNIQUE KEY
或使用唯一索引声明唯一列。
在您的情况下,您的连接表有一个额外的代理主键,我认为这是不必要的,因为其他三个列唯一地定义了该行。 即使你需要它,你也不必聚集在它上面。 您可以使用与 PK 完全分开的聚集索引(它充当包含所有列的索引)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.