Saya memiliki struktur database yang mirip dengan ini,
CREATE TABLE [dbo].[Dispatch](
[DispatchId] [int] NOT NULL,
[ContractId] [int] NOT NULL,
[DispatchDescription] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Dispatch] PRIMARY KEY CLUSTERED
(
[DispatchId] ASC,
[ContractId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DispatchLink](
[ContractLink1] [int] NOT NULL,
[DispatchLink1] [int] NOT NULL,
[ContractLink2] [int] NOT NULL,
[DispatchLink2] [int] NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (1, 1, N'Test')
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (2, 1, N'Test')
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (3, 1, N'Test')
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (4, 1, N'Test')
GO
INSERT [dbo].[DispatchLink] ([ContractLink1], [DispatchLink1], [ContractLink2], [DispatchLink2]) VALUES (1, 1, 1, 2)
GO
INSERT [dbo].[DispatchLink] ([ContractLink1], [DispatchLink1], [ContractLink2], [DispatchLink2]) VALUES (1, 1, 1, 3)
GO
INSERT [dbo].[DispatchLink] ([ContractLink1], [DispatchLink1], [ContractLink2], [DispatchLink2]) VALUES (1, 3, 1, 2)
GO
Inti dari tabel DispatchLink adalah untuk menghubungkan dua catatan pengiriman bersama. Ngomong-ngomong saya menggunakan kunci primer komposit di meja pengiriman saya karena peninggalan, jadi saya tidak bisa mengubahnya tanpa banyak rasa sakit. Juga tabel tautan mungkin bukan cara yang benar untuk melakukannya? Tapi sekali lagi warisan.
Jadi pertanyaan saya, jika saya menjalankan kueri ini
select * from Dispatch d
inner join DispatchLink dl on d.DispatchId = dl.DispatchLink1 and d.ContractId = dl.ContractLink1
or d.DispatchId = dl.DispatchLink2 and d.ContractId = dl.ContractLink2
Saya tidak pernah bisa mendapatkannya untuk melakukan pencarian indeks di tabel DispatchLink. Itu selalu melakukan pemindaian indeks penuh. Itu bagus dengan beberapa catatan, tetapi ketika Anda memiliki 50.000 di tabel itu, memindai 50000 catatan dalam indeks sesuai dengan rencana kueri. Itu karena ada 'ands' dan 'ors' di klausa join, tapi saya tidak bisa mengerti mengapa SQL tidak dapat melakukan beberapa pencarian indeks, satu untuk sisi kiri dari 'atau', dan satu untuk sisi kanan 'atau'.
Saya ingin penjelasan untuk ini, bukan saran untuk membuat kueri lebih cepat kecuali itu bisa dilakukan tanpa menyesuaikan kueri. Alasannya adalah bahwa saya menggunakan kueri di atas sebagai gabungan filter gabung replikasi, jadi saya tidak bisa menambahkan jenis permintaan lain sayangnya.
UPDATE: Misalnya ini adalah jenis indeks yang telah saya tambahkan,
CREATE NONCLUSTERED INDEX IDX1 ON DispatchLink (ContractLink1, DispatchLink1)
CREATE NONCLUSTERED INDEX IDX2 ON DispatchLink (ContractLink2, DispatchLink2)
CREATE NONCLUSTERED INDEX IDX3 ON DispatchLink (ContractLink1, DispatchLink1, ContractLink2, DispatchLink2)
Jadi ia menggunakan indeks, tetapi melakukan pemindaian indeks di seluruh indeks, jadi 50000 catatan itu memindai 50.000 catatan dalam indeks.
DispatchLink
meja?Jawaban:
Pengoptimal dapat mempertimbangkan banyak alternatif rencana (termasuk yang dengan banyak pencarian) tetapi untuk disjungsi (
OR
predikat), pengoptimal tidak mempertimbangkan rencana yang melibatkan persimpangan indeks secara default. Diberikan indeks:Kami dapat memaksa pencarian indeks (dengan asumsi SQL Server 2008 atau yang lebih baru):
Menggunakan data sampel Anda, biaya pencarian paket di 0,0332551 unit dibandingkan dengan 0,0068057 untuk rencana pemindaian:
Ada segala macam kemungkinan penulisan ulang dan petunjuk yang bisa kita coba. Salah satu contoh penulisan ulang untuk mempromosikan opsi yang tidak dipertimbangkan oleh optimizer untuk paket aslinya adalah:
Rencana eksekusi ini tidak mencari indeks kedua jika menemukan kecocokan pada yang pertama:
Ini mungkin berkinerja sangat sedikit lebih baik daripada paket default
FORCESEEK
.Tanpa menambahkan indeks baru, kami juga dapat memaksa pencarian ke dalam tabel Pengiriman:
Ini mungkin lebih baik atau lebih buruk daripada contoh pertama tergantung pada hal-hal seperti berapa banyak baris di setiap tabel. The
APPLY + TOP
perbaikan masih mungkin:sumber