Usuwanie danych z bazy przy użyciu kursora

0

Załóżmy taką sytuację, że trzeba oczyścić tabelę zamówień z przeterminowanych danych, czyli np. takich, których CreationDate jest starsze niż doba. No i w bazie chodzi sobie jakiś job, który uruchamia procedurę, a w procedurze... no właśnie. Ja bym się spodziewał czegoś w rodzaju:

DELETE FROM Orders WHERE CreationDate < DATEADD(DAY, -1, SYSDATETIMEOFFSET())

Tymczasem w procedurze zastałem pobranie rekordów do tabeli tymczasowej i kursor, który jedzie po ID i usuwa rekordy po kolei. Wygląda to dziwnie, no ale się nie znam, więc pytanie do ekspertów - to potencjalnie może mieć jakiś głębszy sens wydajnościowy/transakcyjny czy po prostu jakiegoś ambitnego stażystę poniosły emocje?

0

A nie ma tam jakiś dodatkowych sprawdzeń. Czy ostateczny efekt jest tylko taki, że usuwa dane z bazy jak prosty delete? Trochę to wygląda na robotę satżysty, który nie umiał dodać odpowiedniego wherw do deleta

0

@Tomek Pycia: Ale tam dokładnie ten sam prawidłowy where jest w select do tabeli tymczasowej, więc umiał go napisać. ;)

@WeiXiao: baza to MSSQL.

1

na pierwszy rzut wydaje się bez sensu, już użycie kursora otwiera nóż w kieszeni...

Tak serio nie widzę sensu, może to pozostałość gdzie to każde id było dodatkowo sprawdzane i zrezygnowano z tego sprawdzania...

0

albo jakoś logowane co jest usuwane. Strzelam, że taki sposób jest z 5-10 (w zależności jak transakcje są zrealizowane) razy wolniejszy niż jeden delete

0

Czy na tabeli orders jest trigger na zdarzeniu delete? Może ktoś chciał uzyskać efekt for each row? Jak nie to albo ctrl+c, ctrl+v albo fantazja stażysty
Drugi pomysł - choć nie wiem czy coś takiego jest na mssql - to weryfikacja na wzór VPD z oracle:
https://docs.oracle.com/cd/B19306_01/network.102/b14266/apdvpoli.htm#i1008538

2

Są dwie opcje:
a) głupie rozwiązanie (99%)
b) mega sprytne (1% - ale i tak głupie, bo nie wiadomo o co co chodzi ;) )

Generalnie "row-by-row processing" po stronie bazy jest słabym podejściem dla większej ilości danych.

Istotne wydaje mi się zrozumienie, czy po delecie robi commita i zamiast jednej dużej transakcji jest dużo małych transakcji? Jeśli commit co przetworzenie rekordu z kursora (albo co 100/1000 etc.), to może ktoś chciał minimalizować rozmiar pojedynczej transakcji, bo np. gdzieś w tle działa jakaś replikacja danych. Może chodziło o minimalizowanie czasu locków?

Rzadko mam do czynienia z MS SQLem i nie pamiętam jak działa mechanizm lockowania (ale z tego co pamiętam, to MS SQL nie potrafił w non-blocking jeśli chodzi o odczyty/zapisy - odczyty nie blokują zapisów i zapisy nie blokują odczytów - Oracle chwalił się, że potrafi - pewnie opatentował i MS SQL dlatego nie potrafi(ł), tylko miał inaczej - nie znaczy, że gorzej. Taka dygresja :) )

1

w MSSQL są już trzy dostępne tryby lockowania:

  • domyślnie jest włączony ten w którym odczyty blokują się z zapisami,
  • można włączyć snapshot Isolation, wtedy odczyty nie blokują się z zapisami, ale zapisy ciągle wymagają blokad, domyślnie ten jest włączony w Azure
  • natomiast przy użyciu memory optimized tables jest w pełni optymistyczny model, nie ma żadnych blokad nawet pomiędzy zapisami

przy takim podejściu (kursorowym) replikacja raczej będzie trwała dłużej niż krócej, ale pomysł że jest to sposób na uniknięcie dłuższych blokad brzmi jak najbardziej sensownie. Może na tej tabeli jest takie obciążenie że nie da się skasować jednocześnie wielu wierszy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1