Giả sử tôi có một bảng Foo
có các cột ID1, ID2
và khóa chính tổng hợp được xác định ID2, ID1
. (Tôi hiện đang làm việc với một sản phẩm Trung tâm Hệ thống có một số bảng được xác định theo cách này với các cột khóa chính được liệt kê theo thứ tự ngược lại chúng xuất hiện trong định nghĩa bảng.)
CREATE TABLE dbo.Foo(
ID1 int NOT NULL,
ID2 int NOT NULL,
CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED (ID2, ID1)
);
GO
-- Add a row and update stats so that histogram isn't empty
INSERT INTO Foo (ID1, ID2) VALUES (1,2);
UPDATE STATISTICS dbo.Foo;
Các key_ordinal
cột trong sys.index_columns
chương trình các cột chỉ số theo thứ tự chúng được khai báo trong khóa chính tổng hợp:
SELECT t.name, i.name, c.column_id, c.name, ic.index_column_id, ic.key_ordinal
FROM sys.tables AS t
JOIN sys.indexes AS i
ON t.[object_id] = i.[object_id]
JOIN sys.index_columns AS ic
ON ic.[object_id] = i.[object_id]
AND ic.index_id = i.index_id
JOIN sys.columns AS c
ON ic.column_id = c.column_id
AND ic.[object_id] = c.[object_id]
WHERE t.name = 'Foo';
Biểu đồ cũng hiển thị số liệu thống kê theo thứ tự tương tự:
DBCC SHOW_STATISTICS ('Foo',PK_Foo);
Tuy nhiên, sys.stats_columns
hiển thị các cột được liệt kê theo thứ tự nghịch đảo ( ID1, ID2
).
SELECT s.name, sc.stats_column_id, c.name
FROM sys.stats AS s
JOIN sys.stats_columns AS sc
ON s.stats_id = sc.stats_id
AND s.[object_id] = sc.[object_id]
JOIN sys.columns AS c
ON c.[object_id] = s.[object_id]
AND c.column_id = sc.column_id
JOIN sys.objects AS o
ON o.[object_id] = c.[object_id]
WHERE o.name = 'Foo'
AND s.name = 'PK_Foo';
Books Online cho biết stats_column_id
là "thứ tự dựa trên 1 trong tập hợp các cột thống kê", vì vậy tôi đã mong đợi giá trị 1 sẽ trỏ đến cột đầu tiên trong đối tượng thống kê.
Đây có phải là một lỗi trong sys.stats_columns
hoặc một sự hiểu lầm từ phía tôi?
Tôi đã xác minh hành vi này xảy ra trên các bản dựng hiện tại của SQL Server 2005, 2008, 2008 R2, 2012 và 2014.
sys.stats_columns
dường như phản ánh thứ tự trong đối tượng thống kê trong các tình huống khác, ví dụ:
CREATE TABLE dbo.Foo2(
ID1 int NOT NULL,
ID2 int NOT NULL,
ID3 int NULL,
String VARCHAR(10) NULL,
CONSTRAINT [PK_Foo2] PRIMARY KEY CLUSTERED (ID2, ID1)
);
GO
INSERT INTO Foo2 (ID1, ID2, ID3, String) VALUES (1,2,3,'String');
CREATE STATISTICS ST_Test ON Foo2 (ID3, String);
CREATE STATISTICS ST_Test2 ON Foo2 (String, ID3);
DBCC SHOW_STATISTICS ('Foo2',ST_Test);
DBCC SHOW_STATISTICS ('Foo2',ST_Test2);
SELECT s.name, sc.stats_column_id, c.name
FROM sys.stats AS s
JOIN sys.stats_columns AS sc
ON s.stats_id = sc.stats_id
AND s.[object_id] = sc.[object_id]
JOIN sys.columns AS c
ON c.[object_id] = s.[object_id]
AND c.column_id = sc.column_id
JOIN sys.objects AS o
ON o.[object_id] = c.[object_id]
WHERE o.name = 'Foo2'
AND s.name LIKE 'ST_Test%';
Đây là một ví dụ khác sys.stats_columns
xuất hiện để trả về dữ liệu chính xác, lần này là để thống kê về một chỉ mục:
--drop table dbo.Foo3
CREATE TABLE dbo.Foo3(
ID1 int NOT NULL,
ID2 int NOT NULL,
ID3 int NULL,
String VARCHAR(10) NULL,
CONSTRAINT [PK_Foo3] PRIMARY KEY CLUSTERED (ID2, ID1)
);
GO
INSERT INTO Foo3 (ID1, ID2, ID3, String) VALUES (1,2,3,'String');
UPDATE STATISTICS Foo3;
CREATE INDEX IX_Test ON Foo3 (ID3, String);
CREATE INDEX IX_Test2 ON Foo3 (String, ID3);
DBCC SHOW_STATISTICS ('Foo3',IX_Test);
DBCC SHOW_STATISTICS ('Foo3',IX_Test2);
SELECT s.name, sc.stats_column_id, c.name
FROM sys.stats AS s
JOIN sys.stats_columns AS sc
ON s.stats_id = sc.stats_id
AND s.[object_id] = sc.[object_id]
JOIN sys.columns AS c
ON c.[object_id] = s.[object_id]
AND c.column_id = sc.column_id
JOIN sys.objects AS o
ON o.[object_id] = c.[object_id]
WHERE o.name = 'Foo3'
AND s.name LIKE 'IX_Test%';
stats_column_id
trongsys.stats_columns
dường như không làm những gì nó nói nó. Bởi vì bạn đang ủng hộ một chỉ mục, tôi sẽ tuân theo thứ tự cột chỉ mục. Nếu bạn chỉ nhìn vào các đối tượng thống kê thì có vẻ như đóindex_col()
là lựa chọn tốt nhất hiện tại