2008-11-06 41 views
19

Tôi đang cố gắng tìm ra cách tốt nhất để chèn bản ghi vào một bảng duy nhất nhưng chỉ khi mục chưa tồn tại. KEY trong trường hợp này là trường NVARCHAR (400). Đối với ví dụ này, giả sử đó là tên của một từ từ trong Từ điển tiếng Anh Oxford/chèn từ điển fav của bạn tại đây. Ngoài ra, tôi đoán tôi sẽ cần phải làm cho trường Word một khóa chính. (bảng cũng sẽ có một mã định danh duy nhất PK).SQL Server - Cách chèn một bản ghi và đảm bảo rằng nó là duy nhất

Vì vậy, tôi có thể nhận được những từ này mà tôi cần thêm vào bảng ...

ví dụ:

  • Cát
  • Chó
  • Foo
  • Bar
  • PewPew
  • vv ...

Vì vậy, theo truyền thống, tôi sẽ thử như sau (pseudo code)

SELECT WordID FROM Words WHERE Word = @Word 
IF WordID IS NULL OR WordID <= 0 
    INSERT INTO Words VALUES (@Word) 

tức là. Nếu từ không tồn tại, sau đó chèn nó vào.

Bây giờ .. vấn đề tôi lo lắng là chúng tôi đang nhận được rất nhiều lượt truy cập .. vì vậy có thể từ đó có thể được chèn từ một quá trình khác giữa SELECT và INSERT .. sau đó ném một lỗi ràng buộc? (ví dụ: Race Condition).

sau đó tôi nghĩ rằng tôi có thể có thể làm như sau ...

INSERT INTO Words (Word) 
SELECT @Word 
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word) 

về cơ bản, chèn một từ khi nó không tồn tại.

Cú pháp sai sang một bên, tôi không chắc liệu điều này là xấu hay tốt vì cách nó khóa bảng (nếu có) và không phải là người biểu diễn trên một bảng mà nó nhận được đọc lớn và nhiều viết .

Vì vậy - bạn nghĩ gì về Sql?

Tôi đã hy vọng có một chèn đơn giản và 'bắt' cho bất kỳ lỗi nào được ném.

Trả lời

24

giải pháp của bạn:

INSERT INTO Words (Word) 
    SELECT @Word 
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word) 

... là khoảng tốt như nó được. Bạn có thể đơn giản hóa điều này theo cách này:

INSERT INTO Words (Word) 
    SELECT @Word 
WHERE NOT EXISTS (SELECT * FROM Words WHERE Word = @Word) 

... vì EXISTS không thực sự cần trả lại bất kỳ bản ghi nào, vì vậy trình tối ưu hóa truy vấn sẽ không bận tâm xem bạn đang yêu cầu trường nào.

Như bạn đã đề cập, tuy nhiên, điều này không thực sự đặc biệt, bởi vì nó sẽ khóa toàn bộ bảng trong INSERT. Ngoại trừ việc đó, nếu bạn thêm một chỉ mục duy nhất (nó không cần phải là khóa chính) vào Word, thì nó sẽ chỉ cần khóa các trang liên quan.

Tùy chọn tốt nhất của bạn là mô phỏng tải dự kiến ​​và xem hiệu suất với Trình cấu hình máy chủ SQL. Như với bất kỳ lĩnh vực nào khác, tối ưu hóa sớm là một điều xấu. Xác định số liệu hiệu suất được chấp nhận và sau đó đo lường trước khi thực hiện bất kỳ thứ gì khác.

Nếu điều đó vẫn không mang lại cho bạn hiệu suất phù hợp, thì có rất nhiều kỹ thuật từ trường lưu trữ dữ liệu có thể giúp ích.

+1

Có sự khác biệt về hiệu suất giữa EXISTS (SELECT * FROM ...) và EXISTS (SELECT 1 FROM ...) không? Tôi luôn luôn có xu hướng sử dụng sau này, để tránh các ngôi sao - là có lợi hoặc là tất cả như nhau? – Tomalak

+0

Tôi nghi ngờ rằng tất cả đều giống nhau, nhưng bạn phải kích hoạt nó trong SQL Server Profiler để chắc chắn. –

+0

Tôi cũng không bao giờ chọn * trong các lựa chọn của mình, nhưng luôn luôn chỉ định trường trả về/giá trị. –

3

Nếu bạn đang sử dụng MS SQL Server, bạn có thể tạo một unique index trên các cột của bảng của bạn mà cần phải là duy nhất (ghi here):

CREATE UNIQUE [ CLUSTERED | NONCLUSTERED ] INDEX <index_name> 
    ON Words (word [ ASC | DESC ]) 

Chỉ định Clustered hoặc NonClustered, tùy thuộc vào trường hợp của bạn. Ngoài ra, nếu bạn muốn nó được sắp xếp (để cho phép tìm kiếm nhanh hơn), hãy chỉ định ASC hoặc DESC cho thứ tự sắp xếp.

Xem here, nếu bạn muốn tìm hiểu thêm về kiến ​​trúc chỉ mục.

Nếu không, bạn có thể sử dụng UNIQUE CONSTRAINTS như tài liệu here:

ALTER TABLE Words 
ADD CONSTRAINT UniqueWord 
UNIQUE (Word); 
0

tôi không thể nói chuyện với các nội của MS SQL, nhưng có một điểm của một khóa chính trong SQL là để đảm bảo tính độc đáo. Vì vậy, theo định nghĩa trong các thuật ngữ SQL chung, một khóa chính là một hoặc nhiều trường duy nhất cho một bảng. Mặc dù có nhiều cách khác nhau để thực thi hành vi này (thay thế mục nhập cũ bằng hành động mới so với mục nhập cũ) Tôi sẽ ngạc nhiên nếu MS SQL không có cơ chế thực thi hành vi này và không phải từ chối mục nhập mới. Chỉ cần đảm bảo bạn đặt khóa chính cho trường Word và nó nên hoạt động.

Một lần nữa, tôi từ chối tất cả những kiến ​​thức này từ lập trình MySQL và lớp cơ sở dữ liệu của tôi, vì vậy xin lỗi nếu tôi không hiểu về sự phức tạp của MS SQL.

1

trong khi hạn chế duy nhất là certaily một con đường để đi, bạn cũng có thể sử dụng cho logic chèn của bạn: http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

về cơ bản bạn không đặt bất kỳ ổ khóa trên bảng dưới đây do đó không lo lắng về đọc khi bạn kiểm tra tồn tại sẽ được thực hiện ok.

đó là một mutex trong mã sql.

-1
declare @Error int 

begin transaction 
    INSERT INTO Words (Word) values(@word) 
    set @Error = @@ERROR 
    if @Error <> 0 --if error is raised 
    begin 
     goto LogError 
    end 
commit transaction 
goto ProcEnd 

LogError: 
rollback transaction 
+0

Dude - tôi đã nói trong bài viết mở đầu của tôi rằng tôi không muốn có một chèn câm và sau đó kiểm tra lỗi.Đó không phải là rất thông minh IMO. –

2

Tôi có vấn đề tương tự và đây là cách tôi giải quyết nó

insert into Words 
(selectWord , Fixword) 
SELECT word,'theFixword' 
FROM OldWordsTable 
WHERE 
(
    (word LIKE 'junk%') OR 
    (word LIKE 'orSomthing') 

) 
and word not in 
    (
     SELECT selectWord FROM words WHERE selectWord = word 
    ) 
4

Tôi nghĩ rằng tôi đã tìm thấy một (hoặc ít nhất là nhanh hơn) câu trả lời tốt hơn cho việc này. Tạo chỉ mục như:

CREATE UNIQUE NONCLUSTERED INDEX [IndexTableUniqueRows] ON [dbo].[table] 
(
    [Col1] ASC, 
    [Col2] ASC, 

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ON, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 

Bao gồm tất cả các cột xác định tính duy nhất. Phần quan trọng là IGNORE_DUP_KEY = ON. Điều đó biến chèn không độc đáo thành cảnh báo. SSIS bỏ qua những cảnh báo này và bạn vẫn có thể sử dụng tải nhanh.

Các vấn đề liên quan