it-swarm.asia

SQL Select mengambil terlalu banyak waktu untuk dieksekusi

Ini adalah pemilihan sederhana dari tabel sementara, kiri bergabung dengan tabel yang ada pada kunci utama, dengan dua sub memilih menggunakan top 1 merujuk tabel bergabung.

Dalam kode:

SELECT
    TempTable.Col1,
    TempTable.Col2,
    TempTable.Col3,
    JoinedTable.Col1,
    JoinedTable.Col2,
    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn1,
    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn2,
FROM
    #TempTable as TempTable
LEFT JOIN
    JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND 
    TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
    JoinedTable.WhereColumn IN  (1, 3)

Ini adalah replika persis dari kueri saya.

Jika saya menghapus dua sub seleksi, itu berjalan dengan baik dan cepat. Dengan dua sub pilihan, saya mendapatkan sekitar 100 catatan per detik, yang sangat lambat untuk kueri ini karena harus mengembalikan hampir satu juta catatan.

Saya telah memeriksa untuk melihat apakah setiap tabel memiliki Kunci Utama, semuanya memiliki. Mereka semua memiliki Indeks DAN statistik untuk kolom penting mereka, seperti yang ada di klausa WHERE itu, dan yang ada di klausa GABUNG. Satu-satunya tabel tanpa kunci primer yang ditentukan atau indeks adalah tabel sementara, tetapi itu bukan masalah juga karena itu bukan yang terkait dengan subseleksi yang lambat, dan seperti yang saya sebutkan, tanpa sub seleksi itu berjalan dengan baik.

Tanpa itu TOP 1 ia mengembalikan lebih dari satu hasil, dan memunculkan kesalahan.

Tolong, tolong siapa?

SUNTING :

Jadi rencana eksekusi memberitahuku bahwa aku kehilangan Indeks. Saya telah membuatnya, dan menciptakan kembali beberapa indeks lainnya. Setelah beberapa saat, rencana eksekusi menggunakannya, dan permintaan sekarang berjalan cepat. Satu-satunya masalah adalah saya tidak berhasil melakukan ini lagi di server lain, untuk permintaan yang sama. Jadi solusi saya akan ke PETUNJUK indeks SQL Server yang akan digunakan.

9
Smur

Saya pikir dalam sejuta catatan kueri, Anda harus menghindari hal-hal seperti OUTER JOINS. Saya sarankan Anda menggunakan UNION ALL Daripada LEFT JOIN. Selama saya pikir CROSS APPLY Lebih efisien daripada sub-kueri dalam klausa pilih, saya akan memodifikasi kueri yang ditulis oleh Conard Frix, yang menurut saya benar.

sekarang: ketika saya mulai memodifikasi permintaan Anda, saya perhatikan Anda memiliki klausa WHERE yang mengatakan: JoinedTable.WhereColumn IN (1, 3). dalam hal ini, jika bidangnya nol maka kondisinya akan menjadi salah. lalu mengapa Anda menggunakan LEFT JOIN saat Anda memfilter baris bernilai nol? ganti saja LEFT JOIN Dengan INNER JOIN, saya jamin itu akan menjadi lebih cepat.

tentang INDEX:

harap dicatat bahwa ketika Anda memiliki indeks di atas meja, katakan

table1(a int, b nvarchar)

dan indeks Anda adalah:

nonclustered index ix1 on table1(a)

dan Anda ingin melakukan sesuatu seperti ini:

select a,b from table1
where a < 10

dalam indeks Anda, Anda belum memasukkan kolom b jadi apa yang terjadi?

jika sql-server menggunakan indeks Anda, itu harus mencari dalam indeks, disebut "Index Seek" dan kemudian merujuk ke tabel utama untuk mendapatkan kolom b, disebut "Mencari". Prosedur ini mungkin memakan waktu lebih lama daripada memindai tabel itu sendiri: "Table Scan".

tetapi berdasarkan statistik yang dimiliki sql-server, dalam situasi seperti itu, mungkin tidak menggunakan indeks Anda sama sekali.

jadi pertama-tama periksa Execution Plan untuk melihat apakah indeks digunakan sama sekali.

jika ya atau tidak keduanya, ubah indeks Anda untuk memasukkan semua kolom yang Anda pilih. katakan seperti:

nonclustered index ix1 on table1(a) include(b)

dalam hal ini Look Up tidak diperlukan, dan permintaan Anda akan dieksekusi jauh lebih cepat.

7
Maziar Taheri

Subnya memilih dalam pemilihan kolom Anda yang menyebabkan pengembalian lambat. Anda harus mencoba menggunakan sub-pilihan Anda di gabungan kiri, atau menggunakan tabel turunan seperti yang telah saya tentukan di bawah ini.

Menggunakan Left Joins ke dua instance dari Tabel Ketiga

SELECT
  TempTable.Col1,
  TempTable.Col2,
  TempTable.Col3,
  JoinedTable.Col1,
  JoinedTable.Col2,
  ThirdTable.Col1 AS ThirdTableColumn1,
  ThirdTable2.Col1 AS ThirdTableColumn2
FROM #TempTable as TempTable
LEFT JOIN JoinedTable ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND 
    TempTable.PKColumn 2 = JoinedTable.PKColumn2)
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
WHERE
    JoinedTable.WhereColumn IN  (1, 3)

Menggunakan Tabel Berasal

 SELECT 
      TempTable.Col1,
      TempTable.Col2,
      TempTable.Col3,
      DerivedTable.Col1,
      DerivedTable.Col2,
      DerivedTable.ThirdTableColumn1,
      DerivedTable.ThirdTableColumn2
 FROM #TempTable as TempTable
    LEFT JOIN (SELECT
                 JoinedTable.PKColumn2,
                 JoinedTable.Col1,
                 JoinedTable.Col2,
                 JoinedTable.WhereColumn,
                 ThirdTable.Col1 AS ThirdTableColumn1,
                 ThirdTable2.Col1 AS ThirdTableColumn2
               FROM JoinedTable
               LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
               LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn) 
        DerivedTable ON (TempTable.PKColumn1 = DerivedTable .PKColumn2 AND 
        TempTable.PKColumn2 = DerivedTable.PKColumn2)
    WHERE
        DerivedTable.WhereColumn IN  (1, 3)
6
John Hartsock

Coba beri tanda silang

SELECT
    TempTable.Col1,
    TempTable.Col2,
    TempTable.Col3,
    JoinedTable.Col1,
    JoinedTable.Col2,
    ThirdTableColumn1.col1,
    ThirdTableColumn2.col1

FROM
    #TempTable as TempTable
LEFT JOIN
    JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND 
    TempTable.PKColumn 2 = JoinedTablePKColumn2)

CROSS APPLY
(
        SELECT TOP 1
            ThirdTable.Col1 -- Which is ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn1
CROSS APPLY    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn2,
WHERE
    JoinedTable.WhereColumn IN  (1, 3)

Anda juga dapat menggunakan CTE dan row_number atau kueri inline menggunakan MIN

2
Conrad Frix

Pindahkan bit JOIN dari bagian utama klausa dan letakkan sebagai subselect. Memindahkannya ke bagian WHERE dan JOIN menjamin Anda tidak perlu SELECT TOP 1 berulang-ulang, yang saya percaya adalah alasan untuk lambatnya hte. Jika Anda ingin memeriksa ini, periksa rencana eksekusi.

2
Gregory A Beamer

Referensi ThirdTable, (sub memilih dalam contoh Anda), memerlukan perhatian indeks yang sama seperti bagian lain dari kueri.

Terlepas dari apakah Anda menggunakan sub pilih:

(
    SELECT TOP 1
        ThirdTable.Col1 -- Which is ThirdTable's Primary Key
    FROM
        ThirdTable
    WHERE
        ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
    SELECT TOP 1
        ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
    FROM
        ThirdTable
    WHERE
        ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,

LEFT BERGABUNG (seperti yang diusulkan oleh John Hartsock):

LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn

LINTAS BERLAKU (seperti yang diusulkan oleh Conrad Frix):

CROSS APPLY
(
        SELECT TOP 1
            ThirdTable.Col1 -- Which is ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn1
CROSS APPLY    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn2

Anda perlu memastikan covering indexes didefinisikan untuk ThirdTable.SomeColumn dan ThirdTable.SomeOtherColumn dan indeksnya unik. Ini berarti Anda harus lebih lanjut memenuhi syarat referensi ThirdTable untuk menghilangkan pemilihan beberapa baris dan meningkatkan kinerja. Pilihan sub selects, LEFT JOIN, atau CROSS APPLY tidak akan masalah sampai Anda meningkatkan selektivitas untuk ThirdTable.SomeColumn dan ThirdTable.SomeOtherColumn dengan memasukkan lebih banyak kolom untuk memastikan selektivitas unik. Sampai saat itu, saya berharap kinerja Anda akan terus menderita.

covering index topik diperkenalkan dengan baik oleh Maziar Taheri; sementara tidak mengulangi pekerjaannya, saya menekankan perlunya untuk mengambil hati menggunakan indeks yang meliputi.

Singkatnya: Tingkatkan selektivitas untuk ThirdTable.SomeColumn dan ThirdTable.SomeOtherColumn kueri (atau bergabung) dengan menambahkan kolom dalam-tabel terkait untuk memastikan kecocokan baris yang unik. Jika ini tidak memungkinkan, maka Anda akan terus mengalami masalah kinerja karena mesin sibuk menarik baris yang kemudian dibuang. Ini berdampak pada i/o, cpu, dan, akhirnya, rencana eksekusi Anda.

2
Robert Miller