Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Tindak lanjut #1 pada pencarian wildcard terkemuka

Dalam posting terakhir saya, "Salah satu cara untuk mendapatkan pencarian indeks untuk wildcard terkemuka," saya menyebutkan bahwa Anda akan membutuhkan pemicu untuk menangani pemeliharaan fragmen yang saya rekomendasikan. Beberapa orang telah menghubungi saya untuk menanyakan apakah saya dapat menunjukkan pemicu tersebut.

Untuk menyederhanakan dari posting sebelumnya, mari kita asumsikan kita memiliki tabel berikut – satu set Perusahaan, dan kemudian tabel CompanyNameFragments yang memungkinkan pencarian pseudo-wildcard terhadap substring dari nama perusahaan:

CREATE TABLE dbo.Companies
(
  CompanyID  int CONSTRAINT PK_Companies PRIMARY KEY,
  Name       nvarchar(100) NOT NULL
);
GO
 
CREATE TABLE dbo.CompanyNameFragments
(
  CompanyID int NOT NULL,
  Fragment  nvarchar(100) NOT NULL
);
 
CREATE CLUSTERED INDEX CIX_CNF ON dbo.CompanyNameFragments(Fragment, CompanyID);

Mengingat fungsi ini untuk menghasilkan fragmen (satu-satunya perubahan dari artikel asli adalah saya telah meningkatkan @input untuk mendukung 100 karakter):

CREATE FUNCTION dbo.CreateStringFragments( @input nvarchar(100) )
RETURNS TABLE WITH SCHEMABINDING
AS
  RETURN 
  (
    WITH x(x) AS 
    (
      SELECT 1 UNION ALL SELECT x+1 FROM x WHERE x < (LEN(@input))
    )
    SELECT Fragment = SUBSTRING(@input, x, LEN(@input)) FROM x
  );
GO

Kita dapat membuat satu pemicu yang dapat menangani ketiga operasi:

CREATE TRIGGER dbo.Company_MaintainFragments
ON dbo.Companies
FOR INSERT, UPDATE, DELETE
AS
BEGIN
  SET NOCOUNT ON;
 
  DELETE f FROM dbo.CompanyNameFragments AS f
    INNER JOIN deleted AS d 
    ON f.CompanyID = d.CompanyID;
 
  INSERT dbo.CompanyNameFragments(CompanyID, Fragment)
    SELECT i.CompanyID, fn.Fragment
    FROM inserted AS i 
    CROSS APPLY dbo.CreateStringFragments(i.Name) AS fn;
END
GO

Ini berfungsi tanpa memeriksa jenis operasi apa yang terjadi karena:

  • Untuk UPDATE atau DELETE, DELETE akan terjadi – untuk UPDATE, kami tidak akan repot-repot mencoba mencocokkan fragmen yang akan tetap sama; kami hanya akan meledakkan mereka semua, sehingga mereka dapat diganti secara massal. Untuk INSERT, pernyataan DELETE tidak akan berpengaruh, karena tidak akan ada baris di deleted .
  • Untuk INSERT atau UPDATE, INSERT akan terjadi. Untuk DELETE, pernyataan INSERT tidak akan berpengaruh, karena tidak akan ada baris di inserted .

Sekarang, untuk memastikannya berfungsi, mari lakukan beberapa perubahan pada Companies tabel dan kemudian periksa dua tabel kami.

-- First, let's insert two companies 
-- (table contents after insert shown in figure 1 below)
 
INSERT dbo.Companies(Name) VALUES(N'Banana'), (N'Acme Corp');
 
-- Now, let's update company 2 to 'Orange' 
-- (table contents after update shown in figure 2 below):
 
UPDATE dbo.Companies SET Name = N'Orange' WHERE CompanyID = 2;
 
-- Finally, delete company #1 
-- (table contents after delete shown in figure 3 below):
 
DELETE dbo.Companies WHERE CompanyID = 1;
Gambar 1: Isi tabel awal Gambar 2: Isi tabel setelah pembaruan Gambar 3: Isi tabel setelah dihapus

Peringatan (untuk orang-orang integritas referensial)

Perhatikan bahwa jika Anda mengatur kunci asing yang tepat di antara dua tabel ini, Anda harus menggunakan pemicu alih-alih untuk menangani penghapusan, jika tidak, Anda akan mengalami masalah ayam dan telur – Anda tidak dapat menunggu sampai *setelah* induk baris dihapus untuk menghapus baris anak. Jadi, Anda harus menyiapkan ON DELETE CASCADE (yang saya pribadi cenderung tidak suka), atau dua pemicu Anda akan terlihat seperti ini (pemicu setelahnya masih harus melakukan pasangan DELETE/INSERT dalam kasus UPDATE):

CREATE TRIGGER dbo.Company_DeleteFragments
ON dbo.Companies
INSTEAD OF DELETE
AS
BEGIN
  SET NOCOUNT ON;
 
  DELETE f FROM dbo.CompanyNameFragments AS f
    INNER JOIN deleted AS d
    ON f.CompanyID = d.CompanyID;
 
  DELETE c FROM dbo.Companies AS c
    INNER JOIN deleted AS d
    ON c.CompanyID = d.CompanyID;
END
GO
 
CREATE TRIGGER dbo.Company_MaintainFragments
ON dbo.Companies
FOR INSERT, UPDATE
AS
BEGIN
  SET NOCOUNT ON;
 
  DELETE f FROM dbo.CompanyNameFragments AS f
    INNER JOIN deleted AS d
    ON f.CompanyID = d.CompanyID;
 
  INSERT dbo.CompanyNameFragments(CompanyID, Fragment)
    SELECT i.CompanyID, fn.Fragment
    FROM inserted AS i
    CROSS APPLY dbo.CreateStringFragments(i.Name) AS fn;
END
GO

Ringkasan

Pos ini ditujukan untuk menunjukkan betapa mudahnya menyiapkan pemicu yang akan mempertahankan dapat dicari fragmen string untuk meningkatkan pencarian wildcard, setidaknya untuk string berukuran sedang. Sekarang, saya masih tahu bahwa jenis ini dianggap sebagai ide yang aneh, tetapi saya terus membicarakannya karena saya yakin ada kasus penggunaan yang baik di luar sana.

Dalam posting saya berikutnya, saya akan menunjukkan bagaimana melihat dampak dari pilihan ini:Anda dapat dengan mudah mengatur beban kerja yang representatif untuk membandingkan biaya sumber daya untuk mempertahankan fragmen terhadap penghematan kinerja pada waktu kueri. Saya akan melihat panjang string yang bervariasi serta keseimbangan beban kerja yang berbeda (kebanyakan membaca vs. kebanyakan menulis) dan mencoba menemukan titik manis dan zona bahaya.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Membatasi fleksibilitas Data dalam database NoSQL

  2. ScyllaDB Trends – Bagaimana Pengguna Menyebarkan Basis Data Besar Real-Time

  3. Cara Mengekspor Data ke File Datar dengan Utilitas BCP dan Mengimpor data dengan Sisipan Massal

  4. Statistik Penantian Lutut :PAGELATCH

  5. Tabel Ubah SQL