왜 0.00005초를 낭비하는 것은 여전히 나쁜 생각입니까

15012 단어 sqldatabasebeginners
Azure Databricks/Apache Spark를 사용하여 Azure SQL에 데이터를 올바르게 불러오는 방법에 대한 일련의 게시물과 예시를 준비하고 있습니다. 저는 곧 이 게시물과 예시를 발표하기 시작할 것입니다. 그러나 많은 상황에서 특히 데이터 공간의 새로운 개발자들에게 좋은 테이블 디자인이라는 선결 조건이 무시되었다는 것을 오늘 깨달았습니다.

Wait! If you're not a Apache Spark user you might think this post is not for you. Please read on, it will be just a couple of minutes, and you will find something help also for you, I promise.


좋은 테이블 디자인, 이런 상황에서 규범화, 최상의 데이터 유형에 대한 연구 또는 모두가 알고 있는 다른 기술...아니오, 그런 거 아니에요.그것들은 여전히 절대적으로 유용하고 격려를 받지만, 지금은 그것을 한쪽에 놓고, 우리로 하여금 더욱 간단한 일에 전념하게 한다.
더 간단하지만 상술한 견본을 구축하는 데 사용된 사례에서 영향은 300% 이다.네, 300%입니다.아주 간단한 일을 바꾸면, 나는 성능을 세 배로 향상시킬 수 있다.

문자열을 올바르게 처리
이해해야 할 중점은 우리가 일부 일을 소홀히 하면 아주 작은 일일 수도 있고 데이터가 증가할 때 미세한 오류나 좋지 않은 결정은 그 비용을 표의 모든 줄에 적용할 수도 있다는 것이다.따라서 데이터가 늘어나기 시작하면 성능의 영향을 무시할 수 없는 것이 엉망이 된다.이것은 데이터베이스의 주요 도전이다.데이터의 증가와 변화
내가 지금 토론하고자 하는 구체적인 예시에서 정확한 데이터 형식을 사용하여 문자열 데이터를 저장하는 것은 매우 중요하다.니가 하나면NET 개발자는 문자열을 수천 번 또는 수백만 번 만들거나 조작해야 할 경우 StringBuilder instead of simpler String objects을 사용하는 데 익숙해졌을 수 있습니다.StringBuilder의 최적화 정도가 훨씬 높아 String 대상만 사용해도 같은 결과를 얻을 수 있다.
Azure SQL에서는 varchar(max) 또는 varchar(n)을 사용할 수 있습니다.varchar(max)을 사용하면 최대 2GB의 데이터를 저장할 수 있습니다.varchar(n)을 사용하면 최대 n바이트를 저장할 수 있지만 8000바이트를 초과할 수는 없습니다.같은 논리도 nvarchar(문자당 2바이트로 제한됨)에 적용되지만 이 경우 문자열은 UTF-16 인코딩을 사용합니다.

모델, 누가 신경 써요?
데이터 세계에 가까운 개발자라면 문자열의 크기를 지정하는 것은 고대에만 의미가 있다는 인상을 받을 수 있습니다.만약 네가 이 이상한 반 바이트의 물건을 들어 본 적이 있다면, 많든 적든 nibble과 같다.
우리가 거의 천 메가바이트를 공짜로 얻었으니 문자열의 크기를 지정하는 것은 중요하지 않다.이런 마음가짐으로 아래의 이런 표는 충분해 보입니다(간단하게 보기 위해서는TPC-H 기준 중의 한 표를 사용했기 때문에 이런 이상한 열명을 용서해 주십시오).
create table [dbo].[LINEITEM]
(
    [L_ORDERKEY] [int] not null,
    [L_PARTKEY] [int] not null,
    [L_SUPPKEY] [int] not null,
    [L_LINENUMBER] [int] not null,
    [L_QUANTITY] [decimal](15, 2) not null,
    [L_EXTENDEDPRICE] [decimal](15, 2) not null,
    [L_DISCOUNT] [decimal](15, 2) not null,
    [L_TAX] [decimal](15, 2) not null,
    [L_RETURNFLAG] [nvarchar](max) not null,
    [L_LINESTATUS] [nvarchar](max) not null,
    [L_SHIPDATE] [date] not null,
    [L_COMMITDATE] [date] not null,
    [L_RECEIPTDATE] [date] not null,
    [L_SHIPINSTRUCT] [nvarchar](max) not null,
    [L_SHIPMODE] [nvarchar](max) not null,
    [L_COMMENT] [nvarchar](max) not null,
    [L_PARTITION_KEY] [int] not null
)  
테이블의 모든 문자열은 다른 언어(C#, Python 및 유사 언어)의 문자열로 간주되며, 문자열의 길이가 거의 무한하다고 가정할 수 있습니다.
데이터베이스 분야에서는 상황이 완전히 다르다.I/O를 최소화하기 위해서 (RAM 이외의 데이터에 접근하는 것이 여전히 당신이 생각할 수 있는 가장 느린 작업이기 때문에) 우리는 몇 차례 최적화를 해서 I/O 한 번에 여러 줄의 데이터를 동시에 읽을 수 있도록 했다.이것이 바로 왜 실제로 data page의 개념이 존재하는가이다.

너는 마땅히 이렇게 해야 한다!
문자열이 무한하지 않다는 것을 알면 다른 최적화를 할 수 있습니다.따라서 만약 우리가 문자열의 잠재적 최대치, 심지어 정확한 크기가 얼마인지 알고 있다면, 우리는 그것을 지정하여 데이터베이스에서 일부 물건을 최적화하는 데 도움을 줄 수 있다.예를 들어, 다음 표와 같이 앞에 표시된 표이지만 더 정확한 문자열 유형 정의가 있습니다.
create table [dbo].[LINEITEM]
(
    [L_ORDERKEY] [int] not null,
    [L_PARTKEY] [int] not null,
    [L_SUPPKEY] [int] not null,
    [L_LINENUMBER] [int] not null,
    [L_QUANTITY] [decimal](15, 2) not null,
    [L_EXTENDEDPRICE] [decimal](15, 2) not null,
    [L_DISCOUNT] [decimal](15, 2) not null,
    [L_TAX] [decimal](15, 2) not null,
    [L_RETURNFLAG] [char](1) not null,
    [L_LINESTATUS] [char](1) not null,
    [L_SHIPDATE] [date] not null,
    [L_COMMITDATE] [date] not null,
    [L_RECEIPTDATE] [date] not null,
    [L_SHIPINSTRUCT] [varchar](25) not null,
    [L_SHIPMODE] [varchar](10) not null,
    [L_COMMENT] [varchar](44) not null,
    [L_PARTITION_KEY] [int] not null
) 
물리적 설계의 측면에서 볼 때 마지막 탁자가 훨씬 낫다.예를 들어 Azure Databricks를 사용하여 데이터를 로드하면 이 점을 직접 볼 수 있습니다.
첫 번째 테이블에 데이터를 로드하는 데 약 7분의 9GB가 소요되지만 두 번째 테이블에서는 정확히 동일한 데이터가 2.5분만 소요됩니다.

Loading data into a table that has been better designed (from a physical modeling point of view) is 3 time faster then loading data in a table not so well optimized.


최대 문자열의 길이를 정확하게 설정하기만 하면 된다는 것을 감안하면 최적화는 충분히 가치가 있다고 생각합니다.

결론
나는 Azure SQL Hyperscale Gen5 8v Core와 Azure Databricks 6.6(Spark 2.4.5, Scala 2.11)에서 실험을 했는데 4개의 워커마다 4개의 노드가 있고 모두 16개의 워커가 병렬적으로 데이터를 Azure SQL에 불러왔다.
따라서 가능한 한 빨리 데이터를 불러올 수 있도록 하는 첫 번째 단계는 가장 적합한 데이터 형식으로 표를 만드는 것입니다. 특히 문자열을 처리할 때입니다.과거에는 메모리가 부족했기 때문에, 우리는 가능한 한 많은 메모리를 절약하기 위해 작은 바이트를 사용했다.
현재 우리는 넉넉한 시대에 살고 있지만 대량의 데이터를 생성하고 조작하기 때문에 한 바이트가 낭비될 때마다 CPU 주기, 네트워크 대역폭, I/O 대역폭, 캐시와 메모리가 낭비된다.작은 것들을 낭비한다. 이 특정한 예에서 나쁜 디자인은 한 줄에 0.000005초, 59692838회 (이것은 나의 예시의 줄 수) 만 영향을 미친다. 무엇이든지.그래서 우리는 이렇게 시작하지 않는다. 당신의 시계가 언제 한 바이트라도 중요한 크기에 도달할지 영원히 알 수 없기 때문에 준비를 하는 것이 가장 좋다.
우리가 방금 한 이 작은 최적화에는 또 좋은 점이 하나 있다.더 좋은 물리적 설계로 인해 읽기 속도도 빨라질 수 있기 때문에 앞에서 설명한 것과 완전히 같다.따라서 여기서 코드를 던지지 않고 몇 분 동안 우리의 모델을 생각하는 것은 윈윈의 결과이다.
다음 테이블에서 이 점을 기억해라!
panumas nikhomkhai, Pexels에 촬영

좋은 웹페이지 즐겨찾기