IT TIP

연관 테이블을 사용하는 것보다 플래그를 비트 마스크로 저장하는 것이 언제 더 낫습니까?

itqueen 2020. 10. 19. 13:47
반응형

연관 테이블을 사용하는 것보다 플래그를 비트 마스크로 저장하는 것이 언제 더 낫습니까?


사용자가 다른 기능 (예 : 읽기, 만들기, 다운로드, 인쇄, 승인 등)을 사용할 수있는 권한이 다른 응용 프로그램을 작업 중입니다. 권한 목록은 자주 변경되지는 않습니다. 이러한 권한을 데이터베이스에 저장하는 방법에 대한 몇 가지 옵션이 있습니다.

어떤 경우에 옵션 2가 더 좋을까요?

옵션 1

연관 테이블을 사용하십시오.

사용자
----
UserId (PK)
이름
학과
허가
----
PermissionId (PK)
이름
User_Permission
----
UserId (FK)
PermissionId (FK)

옵션 2

각 사용자에 대해 비트 마스크를 저장합니다.

사용자
----
UserId (PK)
이름
학과
권한
[Flags]
enum Permissions {
    Read = 1,
    Create = 2,
    Download = 4,
    Print = 8,
    Approve = 16
}

훌륭한 질문!

먼저 "더 나은"에 대한 몇 가지 가정을 해보겠습니다.

디스크 공간에 대해별로 신경 쓰지 않는다고 가정합니다. 비트 마스크는 공간 관점에서 효율적이지만 SQL 서버를 사용하는 경우 그다지 중요하지 않습니다.

나는 당신이 속도에 관심이 있다고 가정하고 있습니다. 비트 마스크는 계산을 사용할 때 매우 빠를 수 있지만 비트 마스크를 쿼리 할 때 인덱스를 사용할 수 없습니다. 이것은 그다지 중요하지 않지만 어떤 사용자가 생성 액세스 권한을 가지고 있는지 알고 싶다면 쿼리는 다음과 같습니다.

select * from user where permsission & CREATE = TRUE

(현재 이동 중에 SQL Server에 액세스 할 수 없었습니다). 이 쿼리는 수학적 연산으로 인해 인덱스를 사용할 수 없습니다. 따라서 사용자가 많은 경우 매우 고통 스러울 것입니다.

나는 당신이 유지 관리에 관심이 있다고 가정하고 있습니다. 유지 관리의 관점에서 비트 마스크는 명시적인 권한을 저장하는 것만 큼 근본적인 문제 도메인만큼 표현 적이 지 않습니다. 데이터베이스를 포함하여 여러 구성 요소에서 비트 마스크 플래그의 값을 거의 확실하게 동기화해야합니다. 불가능하지는 않지만 뒷면에 통증이 있습니다.

따라서 "더 나은"을 평가하는 다른 방법이 없다면 비트 마스크 경로가 정규화 된 데이터베이스 구조에 권한을 저장하는 것만 큼 좋지 않다고 말하고 싶습니다. "조인을해야하기 때문에 더 느리다"는 데 동의하지 않습니다. 데이터베이스가 완전히 작동하지 않는 한이를 측정 할 수 없습니다 (활성 인덱스의 이점이없는 쿼리는 눈에 띄게 수천 개의 레코드로 더 느립니다.)


개인적으로 연관 테이블을 사용합니다.

비트 마스크 필드는 쿼리하고 조인하기가 매우 어렵습니다.

이를 C # 플래그 열거 형에 매핑하고 성능이 향상되면 데이터베이스를 리팩터링 할 수 있습니다.

조기 최적화에 대한 가독성;)


정규화 된 권한을 저장합니다 (즉, 비트 마스크가 아님). 분명히 시나리오에 대한 요구 사항아니지만 (특히 권한이 자주 변경되지 않는 경우) 쿼리를 훨씬 쉽고 명확하게 만듭니다.


없다 명확한 대답은 그래서, 당신을 위해 일하는 무엇 . 그러나 여기에 내 캐치가 있습니다.

다음과 같은 경우 옵션 1 사용

  • 권한이 증가 할 것으로 예상합니다.
  • 데이터베이스 저장 프로 시저 자체에서 권한 검사를 수행해야하는 경우
  • 테이블의 레코드가 엄청나게 증가하지 않도록 수백만 명의 사용자를 기대하지 않습니다.

다음과 같은 경우 옵션 2 사용

  • 권한은 소수로 제한됩니다
  • 수백만 명의 사용자를 기대합니다.

비트 마스크 필드를 사용하여 권한을 저장하는 경우를 생각할 수있는 유일한 경우는 기존 모바일 장치에서와 같이 보유하고있는 물리적 메모리의 양이 실제로 제한 될 때입니다. 사실, 당신이 저장하는 메모리의 양은 그만한 가치가 없습니다. 수백만 명의 사용자에게도 하드 드라이브 공간이 저렴하고 비트 마스크가 아닌 접근 방식을 사용하여 권한 등을 훨씬 쉽게 확장 할 수 있습니다 (누가 어떤 권한을 가지고 있는지보고하는 것에 관한 것입니다.)

One of this biggest headaches I've run into with it is assigning users permissions directly in the database. I know you should try and use the application to administer itself and not-much with application data in general, but sometimes, it's just necessary. Unless the bitmask is actually a character field, and you can easily see what permissions someone has instead of an integer, try explaining to an analyst etc. how to give write access etc. to someone by updating the field.....and pray your arithmetic is correct.


It'll be useful when they won't change in their structure and will always be used together. That way, you have little round trips to the server. They are also good performance-wise because you can affect all the rights in a single assignation of a variable.

I personally don't like them... In some performance intense application, they're still used. I remember implementing a chess-AI using these because you could evaluate a board in a single comparison.. It's a pain to work with.


I would always store it normalized unless the database is merely holding the record for you, and you will never do anything with this besides retrieving and saving. A scenario for this is if upon login, your user's permission string is fetched, and in server code it is processed and cached. In that case it really doesn't matter too much that it's denormalized.

If you're storing it in a string and trying to do work on it at the DB level, you'd have to do some gymnastics to get the permissions for page X out, which can be painful.


I advice against using a bitmask for the following reasons:

  • Index cannot be used efficiently
  • Querying is harder
  • Readability / Maintenance is severely impacted
  • The average developer out there doesn't know what a bitmask is
  • Flexibility is reduced (upper limit to nr of bits in a number)

Depending on your query patterns, planned feature set and data distribution I would go with your option 1, or even something simple as:

user_permissions(
   user_id
  ,read     
  ,create   
  ,download 
  ,print    
  ,approve  
  ,primary key(user_id)
);

Adding a column is a schema modification, but my guess is that adding a privilege "Purge", will require some code to go along with it, so the privileges may not have to be as dynamic as you think.

If you have some sick distribution of data, such as 90% of the user base doesn't have a single permission, the following model also works fine (but falls apart when doing larger scans (one 5-way join vs a single full table scan).

user_permission_read(
   user_id
  ,primary key(user_id)
  ,foreign key(user_id) references user(user_id)
)

user_permission_write(
   user_id
  ,primary key(user_id)
  ,foreign key(user_id) references user(user_id)
)

user_permission_etcetera(
   user_id
  ,primary key(user_id)
  ,foreign key(user_id) references user(user_id)
)

Your queries will run faster using a flags enumeration (bitmask), because you won't need to include a join to the associated table in order to make sense of the value.

참고URL : https://stackoverflow.com/questions/5708239/when-is-it-better-to-store-flags-as-a-bitmask-rather-than-using-an-associative-t

반응형