Podczas naszego ostatniego cotygodniowego spotkania osoba, która nie ma doświadczenia w administrowaniu bazami danych, poruszyła następujące pytanie:
„Czy byłby scenariusz uzasadniający przechowywanie danych w wierszu (ciąg) zamiast kilku wierszy?”
Załóżmy tabelę o nazwie, w countryStates
której chcemy przechowywać stany kraju; Wykorzystam w tym przykładzie USA i nie będę wymieniał wszystkich stanów ze względu na lenistwo.
Tam mielibyśmy dwie kolumny; jeden dzwonił, Country
a drugi dzwonił States
. Jak omówiono tutaj i zaproponowano w odpowiedzi @ srutzky , PK
będzie to kod zdefiniowany w ISO 3166-1 alfa-3 .
Nasz stół wyglądałby tak:
+---------+-----------------------+-------------------------------------------------------+
| Country | States | StateName |
+---------+-----------------------+-------------------------------------------------------+
| USA | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+
Zadając to samo pytanie znajomemu programistom, powiedział, że z punktu widzenia wielkości ruchu danych może to być przydatne, ale nie, jeśli będziemy musieli manipulować tymi danymi. W takim przypadku musiałaby istnieć inteligencja w kodzie aplikacji, która mogłaby przekształcić ten ciąg w listę (powiedzmy, że oprogramowanie, które ma dostęp do tej tabeli, musi utworzyć pole kombi).
Doszliśmy do wniosku, że ten model nie jest zbyt przydatny, ale zacząłem podejrzewać, że może istnieć sposób, aby uczynić go użytecznym.
Chciałbym zapytać, czy któryś z was już widział, słyszał lub robił coś takiego w sposób, który naprawdę działa .
źródło
a;b;c
, użyj przód do analizowania ciąg następnie dostaća
,b
,c
i kontynuować wykonanie robi coś z nimi, może ?. Czuję, że może to odpowiadać jakiejś konkretnej potrzebie w ten sposób ... Z drugiej strony nie. Zawsze możesz przechowywać identyfikatory,Odpowiedzi:
Na początek obecny tytuł pytania odnoszący się do „przechowywania danych jako ciągu zamiast kolumn” jest nieco mylący. Mówiąc o przechowywaniu danych jako ciągów zamiast czegoś innego, zwykle odnosi się to do szeregowania wszystkiego do formatu ciągu zamiast właściwego / silnego typu danych (np.
INT
LubDATETIME
). Ale pytanie o przechowywanie danych jako wielu wartości w jednym polu zamiast w osobnych wierszach jest nieco inne. I szczerze mówiąc, podczas gdy łączenie wartości najłatwiej jest wykonać za pomocą łańcuchów, można to również zrobić za pomocąINT
iBINARY
typów, albo przez maskowanie bitów lub podobnie rezerwowanie pewnych pozycji, aby mieć różne znaczenia. Ponieważ pytamy o drugą interpretację, opierając się na tekście pytania, zajmiemy się tym.Jednym słowem: Nie. Jeśli przechowujesz rzeczywiste punkty danych, spowoduje to tylko ból (pod względem kodu i wydajności), ponieważ jest to niepotrzebną komplikacją. Jeśli jest to wartość, która będzie zawsze przechowywana jako pojedyncza jednostka, aktualizowana jako pojedyncza jednostka i nigdy nie demontowana w bazie danych, może to być w porządku, ponieważ jest mniej więcej analogiczne do przechowywania obrazu lub pliku PDF. W przeciwnym razie każda próba parsowania danych spowoduje unieważnienie przy użyciu jakichkolwiek indeksów (np. Przy użyciu
LIKE '%something%'
lubCHARINDEX
, lubPATINDEX
, lubSUBSTRING
itd.).Jeśli musisz przechowywać osobne wartości w jednym polu w jednym wierszu, istnieją bardziej odpowiednie sposoby: XML lub JSON. Są to możliwe do przeanalizowania formaty ( XML / JSON ), a XML można nawet indeksować . Ale idealnie te dane byłyby przechowywane w odpowiednio wpisanych polach, aby mogły być naprawdę przydatne.
I proszę nie zapominać, że celem RDBMS jest przechowywanie danych w taki sposób, aby można je było pobierać i przetwarzać tak skutecznie, jak to możliwe, w ramach ograniczeń nałożonych przez zgodność z ACID . Pobieranie skonkatenowanych wartości jest wystarczająco złe ze względu na potrzebę parsowania wartości w pierwszej kolejności i nie jest to możliwe do zindeksowania. Ale manipulowanie często oznacza zastąpienie całego obiektu blob tylko w celu zaktualizowania jego części (przy założeniu, że nie istnieje wzorzec do użycia z
REPLACE
funkcją). Typ danych XML pozwala przynajmniej na XML DML dla uproszczonych aktualizacji, choć wciąż nie są one tak szybkie jak zwykła aktualizacja odpowiednio modelowanych danych.Ponadto, biorąc pod uwagę scenariusz taki jak pokazany w powyższym pytaniu, łącząc wszystkie kody stanu razem, nie będziesz w stanie uzyskać klucza obcego (w żadnym kierunku) tych wartości.
A co, jeśli wymagania biznesowe zmieniają się w czasie i musisz śledzić dodatkowe właściwości tych przedmiotów? Jeśli chodzi o „stany”, a co ze stolicami, populacją, porządkiem sortowania lub czymkolwiek innym? Przechowywane poprawnie jako wiersze, możesz dodać więcej kolumn dla dodatkowych właściwości. Jasne, możesz mieć wiele poziomów analizowalnych danych, na przykład,
|StateCode,Capital,Population |StateCode,Capital,Populate|...
ale mam nadzieję, że każdy zauważy, że problem wykładniczo wymyka się spod kontroli. Oczywiście, ten konkretny problem dość łatwo można rozwiązać w formatach XML i JSON, i to jest ich wartość, jak wspomniano powyżej. Ale nadal potrzebujesz bardzo dobrego powodu, aby użyć któregokolwiek z nich jako początkowego sposobu modelowania, ponieważ żadne z nich nigdy nie będzie tak wydajne, jak użycie dyskretnych pól w oddzielnych wierszach.źródło
Użyłem czegoś takiego do bardzo ograniczonego celu. Stworzyliśmy tabelę nagłówków dla plików wyjściowych. Były one specjalnie skonstruowane i były głównie nagłówkami kolumn, ale nie do końca. Dane wyglądały więc podobnie
Zasadniczo wyglądało na to, że jest to lista rozdzielana ograniczeniami. I w pewnym sensie tak było. Ale dla naszych celów był to jeden długi ciąg.
To jest sztuczka tutaj. Jeśli nigdy nie planujesz analizować listy, warto ją zapisać. Jeśli jednak będziesz musiał lub nawet będziesz musiał przeanalizować listę, warto poświęcić więcej miejsca i czasu, aby ją rozdzielić i zapisać w osobnych wierszach.
źródło
Użyłem go raz z raczej małym stołem, na przykład:
A następnie zapisz wartości
CRM,SMS,SELF-CARE
wvalid_channel
.Cały stół ma około 10 rekordów.
valid_channel
zawiera wartości, które powinny znajdować się w tabeli łączącej, która przedstawia relację wiele do wielu. Stółt1
nie będzie intensywnie używany, więc postanowiliśmy pójść tą drogą. W tę decyzję zaangażowana była jednak pewna polityka (patrz poniżej).Ale generalnie unikam tego, to nie jest 3NF.
W miejscu, w którym pracuję, jest obecnie mnóstwo takich kolumn. Ich uzasadnieniem jest to, że ułatwia to ich zapytania: zamiast łączyć trzy tabele za pomocą tabeli łączącej, mogą przejść bezpośrednio do tabeli definicji za pomocą
LIKE
. Na przykładHorrible + na Oracle wyłącza korzystanie z indeksu z powodu uruchamiania
'%,'
.źródło
LIKE
lub zwykłe dołączenie?LIKE
byłoby wolniejsze, szczególnie jeśli dane są odpowiednio modelowane do użyciaTINYINT
pola PK wchannel_def
. Następnie wystarczy porównać pojedynczy bajt między dwiema tabelami. Tutaj musi przeanalizować ciąg znaków, znak po znaku (przynajmniej do momentu spełnienia warunku), i wykonuje wyszukiwanie bez rozróżniania wielkości liter (na podstawie podanej tabeli def nie pokazuje_BIN2
używanego sortowania). To również unieważnia indeksy na SQL Server. Odpowiedziałem na to w mojej odpowiedzi, stwierdzając, że parsowanie nie może używać indeksów. Właśnie zaktualizowałem swoją odpowiedź, aby była jaśniejsza.LIKE
klauzuli i nie dawałaby dziwnych wyników, może nadal powodować inne problemy lub przynajmniej sprawi, że debugowanie będzie trudniejsze / dłuższe). Utrudnia to również aktualizacjęvalid_channels
pola. Nie oznacza to, że to nie działa, po prostu nie ma dobrego powodu, aby to zrobić.Dokonano tego tutaj na SE. Jak pisze Marc Gravell :
Ten „nowy format” był kolejnym krokiem od „starego formatu”, który był nieco inny i został wybrany do korzystania z funkcji wyszukiwania pełnotekstowego programu SQL Server, więc niektóre korzyści nie są istotne, jeśli robisz to od zera.
Prawdopodobnie nie w pełni znormalizowali to ze względu zarówno na ilość pracy, jak i wydajność.
źródło
Cóż, jedną z głównych zalet używania ciągów i innych typów danych jest wysyłanie ich z SQL Server do C #, C, C ++ (itp.) Za pomocą SQLCLR, gdy może być potrzebna sama wydajność. Możesz nawet utworzyć widok lub procedurę przechowywaną do reprezentowania danych relacyjnych nierelacyjnie - tak jak w powyższym przykładzie do tego właśnie celu.
Zobacz ten przykład:
http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/
według Wikipedii: SQL CLR lub SQLCLR (SQL Common Language Runtime) to technologia do obsługi silnika uruchomieniowego Microsoft .NET w języku wspólnym w SQL Server. SQLCLR umożliwia zarządzanie kodem zarządzanym przez środowisko Microsoft SQL Server i uruchamianie go w tym środowisku.
źródło
Moim zdaniem odpowiedź brzmi „nie”. Nie zastosowałem tego podejścia i uniknęłbym go - nie mogę wymyślić powodu, dla którego wybrałem tę trasę. Opierasz się na świecie JSON / NoSQL z tablicą.
W poprzedniej roli mieliśmy podobne wybory projektowe, w których zespół architektów chciał mieć pole „Dane”, które zostało rozdzielone, a następnie przekształcone na binarne. Ostatecznie nie poszliśmy tą drogą z kilku powodów.
Gdybyś musiał dołączyć do tego typu danych, byłoby to jedno brzydkie doświadczenie. Aktualizacja pojedynczych elementów ciągu również byłaby nieprzyjemna.
źródło