Tự tham gia vào khóa chính


9

Xem xét truy vấn này bao gồm Ntự tham gia:

select
    t1.*
from [Table] as t1
join [Table] as t2 on
    t1.Id = t2.Id
-- ...
join [Table] as tN on
    t1.Id = tN.Id

Nó tạo ra một kế hoạch thực hiện với quét chỉ mục N cụm và tham gia hợp nhất N-1.

Thành thật mà nói, tôi không thấy bất kỳ lý do nào để không tối ưu hóa tất cả các phép nối và chỉ thực hiện một lần quét chỉ mục theo cụm, tức là tối ưu hóa truy vấn ban đầu này:

select
    t1.*
from [Table] as t1

Câu hỏi

  • Tại sao tham gia không được tối ưu hóa đi?
  • Có phải về mặt toán học không chính xác khi nói rằng mọi tham gia không thay đổi tập kết quả?

Đã thử nghiệm trên:

  • Phiên bản máy chủ nguồn: SQL Server 2014 (12.0.4213)
  • Phiên bản cơ sở dữ liệu nguồn: Microsoft SQL Server Standard Edition
  • Loại công cụ cơ sở dữ liệu nguồn: Máy chủ SQL độc lập
  • Mức độ tương thích: SQL Server 2008 (100)

Truy vấn không có ý nghĩa; nó chỉ xuất hiện trong đầu tôi và tôi tò mò về nó bây giờ.

Đây là bí quyết với việc tạo bảng và 3 truy vấn: với inner join, với left joinvà hỗn hợp. Bạn cũng có thể nhìn vào kế hoạch thực hiện ở đó, quá.

Có vẻ như left joins bị loại trong kế hoạch thực hiện kết quả trong khi inner joins thì không. Vẫn không hiểu tại sao .

Câu trả lời:


18

Đầu tiên, giả sử đó (id)là khóa chính của bảng. Trong trường hợp này, có, các phép nối là (có thể được chứng minh) dư thừa và có thể được loại bỏ.

Bây giờ đó chỉ là lý thuyết - hay toán học. Để trình tối ưu hóa thực hiện loại bỏ thực tế, lý thuyết phải được chuyển đổi thành mã và được thêm vào trong bộ tối ưu hóa / viết lại / loại bỏ tối ưu hóa. Để điều đó xảy ra, các nhà phát triển (DBMS) phải nghĩ rằng nó sẽ mang lại lợi ích tốt cho hiệu quả và đó là trường hợp đủ phổ biến.

Cá nhân, nó không giống như một (đủ phổ biến). Truy vấn - như bạn thừa nhận - trông khá ngớ ngẩn và người đánh giá không nên để nó vượt qua đánh giá, trừ khi nó được cải thiện và tham gia dự phòng bị xóa.

Điều đó nói rằng, có những truy vấn tương tự trong đó việc loại bỏ xảy ra. Có một bài đăng blog liên quan rất hay của Rob Farley: THAM GIA đơn giản hóa trong SQL Server .

Trong trường hợp của chúng tôi, tất cả những gì chúng tôi phải làm để thay đổi các phép nối thành LEFTtham gia. Xem dbfiddle.uk . Trình tối ưu hóa trong trường hợp này biết rằng phép nối có thể được gỡ bỏ một cách an toàn mà không thể thay đổi kết quả. (Logic đơn giản hóa khá chung chung và không đặc biệt cho việc tự tham gia.)

Trong truy vấn ban đầu tất nhiên, loại bỏ các phép INNERnối cũng không thể thay đổi kết quả. Nhưng việc tự tham gia vào khóa chính không phổ biến vì vậy trình tối ưu hóa không được thực hiện trong trường hợp này. Tuy nhiên, việc tham gia (hoặc tham gia trái) trong đó cột tham gia là khóa chính của một trong các bảng (và thường có ràng buộc khóa ngoài). Điều này dẫn đến một tùy chọn thứ hai để loại bỏ các phép nối: Thêm một ràng buộc khóa ngoài (tự tham chiếu!):

ALTER TABLE "Table"
    ADD FOREIGN KEY (id) REFERENCES "Table" (id) ;

Và voila, các tham gia được loại bỏ! (đã thử nghiệm trong cùng một câu đố): tại đây

create table docs
(id int identity primary key,
 doc varchar(64)
) ;
GO
insert
into docs (doc)
values ('Enter one batch per field, don''t use ''GO''')
     , ('Fields grow as you type')
     , ('Use the [+] buttons to add more')
     , ('See examples below for advanced usage')
  ;
GO
4 hàng bị ảnh hưởng
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    join docs d2 on d2.id=d1.id
    join docs d3 on d3.id=d1.id
    join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | tài liệu                                      
-: | : ----------------------------------------
 1 | Nhập một lô cho mỗi trường, không sử dụng 'GO'
 2 | Các lĩnh vực phát triển khi bạn gõ                  
 3 | Sử dụng các nút [+] để thêm nhiều hơn          
 4 | Xem các ví dụ dưới đây để sử dụng nâng cao    

nhập mô tả hình ảnh ở đây

--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    left join docs d2 on d2.id=d1.id
    left join docs d3 on d3.id=d1.id
    left join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | tài liệu                                      
-: | : ----------------------------------------
 1 | Nhập một lô cho mỗi trường, không sử dụng 'GO'
 2 | Các lĩnh vực phát triển khi bạn gõ                  
 3 | Sử dụng các nút [+] để thêm nhiều hơn          
 4 | Xem các ví dụ dưới đây để sử dụng nâng cao    

nhập mô tả hình ảnh ở đây

alter table docs
  add foreign key (id) references docs (id) ;
GO
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    join docs d2 on d2.id=d1.id
    join docs d3 on d3.id=d1.id
    join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | tài liệu                                      
-: | : ----------------------------------------
 1 | Nhập một lô cho mỗi trường, không sử dụng 'GO'
 2 | Các lĩnh vực phát triển khi bạn gõ                  
 3 | Sử dụng các nút [+] để thêm nhiều hơn          
 4 | Xem các ví dụ dưới đây để sử dụng nâng cao    

nhập mô tả hình ảnh ở đây


2

Trong các thuật ngữ quan hệ, bất kỳ tự tham gia nào mà không đổi tên thuộc tính là không có và có thể được loại bỏ một cách an toàn khỏi các kế hoạch thực hiện. Thật không may, SQL không liên quan và tình huống tự tham gia có thể được loại bỏ bởi trình tối ưu hóa bị giới hạn trong một số ít trường hợp cạnh.

Cú pháp CHỌN của SQL cung cấp quyền ưu tiên hợp lý cho phép chiếu. Các quy tắc phạm vi của SQL cho các tên cột và thực tế là các tên cột trùng lặp và các cột không được đặt tên được cho phép làm cho tối ưu hóa truy vấn SQL khó hơn đáng kể so với tối ưu hóa đại số quan hệ. Các nhà cung cấp SQL DBMS có tài nguyên hữu hạn và phải chọn lọc về loại tối ưu hóa nào họ muốn hỗ trợ.


1

Khóa chính luôn luôn là duy nhất và các giá trị null không được phép, vì vậy, việc nối một bảng với chính nó trên các khóa chính (không phải với khóa phụ tự tham chiếu và không có câu lệnh) sẽ tạo ra cùng số lượng hàng như bảng gốc.

Về lý do tại sao họ không tối ưu hóa nó đi, tôi sẽ nói đó là một trường hợp cạnh mà họ không có kế hoạch hoặc giả định mọi người sẽ không làm. Tham gia một bảng vào chính nó trên các khóa chính duy nhất được đảm bảo không phục vụ mục đích.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.