데이터베이스에서 행 순서 필드를 보다 효율적으로 유지 관리할 수 있는 방법
MariaDB(think MySQL) 데이터베이스가 있으며 행에는position
필드. 이 위치는 변경될 수 있지만 항상 순차적이어야 하며 1부터 시작해야 합니다.
간이 테이블 스키마:
CREATE TABLE `ordered_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner` int(11) NOT NULL,
`data` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
`position` int(11) NOT NULL
PRIMARY KEY (`id`)
)
예를 들어, 사용자는 ID 10의 행을 위치 #1로 이동시킬 수 있습니다.이것은 물론 모든 후속 아이템을 재주문해야 합니다.그렇지 않으면 다음 아이템에 중복이 생깁니다.position
필드입니다. 4개 미만의 쿼리에서 이 작업을 수행할 방법을 찾을 수 없습니다.
현재 사용하고 있는 솔루션은 다음과 같습니다.단순히 정리할 수 있지만, 보다 우아한 재주문 방법이 있다고 생각하지 않을 수 없습니다.이 예에서는 ID32의 행을 사용자 20에 의해 위치 3으로 이동합니다.
- 입수하다
currentPosition
타고SELECT position FROM ordered_data WHERE id = 32
. - 곧 만들어질 공백을 메우려면
UPDATE ordered_data SET position = position - 1 WHERE position > currentPosition AND owner = 20
. - 행의 새 위치(3)를 위한 공간을 만듭니다.
UPDATE ordered_data SET position = position + 1 WHERE position >= 3 AND owner = 20
. - 간격에 맞게 행 위치 업데이트
UPDATE ordered_data SET position = 3 WHERE id = 32
.
어떤 제안도 환영합니다.처음 두 문장을 하위 선택과 결합하면 MySQL이 업데이트 및 선택에 동일한 테이블을 사용하는 것에 대해 불만을 제기하게 됩니다.
소유자당 열 수가 10개를 넘을 가능성은 거의 없습니다.
스텝 순서를 바꾸는 건 생각보다 쉽지 않아요.그러나 한 단계만 더 진행하면 고유한 키를 사용하여 알고리즘이 작동하도록 만들 수 있습니다.(owner, position)
스텝 2에서 엔트리에러의 중복을 피하기 위해서, 일시적으로 할당할 수 있습니다.possition = 0
이동할 항목으로 이동합니다.완전한 알고리즘은 다음과 같습니다.
set @owner = 20;
set @id = 32;
set @new_pos = 3;
-- 1. get current position
set @old_pos = (select position from ordered_data where id = @id);
-- 1.1 "remove" the item from its old position
update ordered_data set position = 0 where id = @id;
-- 2. close the gap at the old position
update ordered_data
set position = position - 1
where position owner = @owner
and position > @old_pos
order by position asc -- important for unique key
-- 3. make space at the new position
update ordered_data
set position = position + 1
where position owner = @owner
and position >= @new_pos
order by position desc -- important for unique key
-- 4. set new position
update ordered_data set position = @new_pos where id = @id;
이 방법(IMHO)은 소규모 그룹에 적합합니다.대용량 데이터 세트의 경우 3단계와 4단계를 최적화하여 한 번에 수행할 수 있습니다.다음의 예를 참조해 주세요.100만 개의 아이템 그룹이 있으며 아이템을 위치 7에서 위치 3으로 이동하려고 합니다.아이템을 '제거'한 후 포지션 8을 1000000으로 업데이트하고 1을 줄여서 갭을 좁힙니다.그런 다음 3의 위치를 999999로 업데이트하고 공간을 확보합니다.이렇게 하면 그룹 전체가 거의 두 번 업데이트되지만, 필요한 것은 포지션 3에서 6으로 증가시키는 것입니다.이를 위해 스텝2와 스텝3을 다음과 같이 대체할 수 있습니다.
if (@new_pos < @old_pos)
update ordered_data
set position = position + 1
where position owner = @owner
and position between @new_pos and @old_pos
order by position desc
else if (@new_pos > @old_pos)
update ordered_data
set position = position - 1
where position owner = @owner
and position between @old_pos and @new_pos
order by position asc
else
-- do nothing
주의: 의사 코드입니다.응용 프로그램 사이트에서 올바른 쿼리를 선택해야 합니다.
단일 쿼리에 결합할 수도 있습니다.
update ordered_data
set position = position + sign(@new_pos - @old_pos)
where position owner = @owner
and position between @new_pos and @old_pos
order by position * sign(@new_pos - @old_pos) desc
그러나 이 경우 엔진은 GROUP BY 절의 인덱스를 사용할 수 없습니다.
언급URL : https://stackoverflow.com/questions/45472587/more-efficient-way-of-maintaining-row-order-field-in-database
'programing' 카테고리의 다른 글
C에서 함수 포인터의 배열을 정의하는 방법 (0) | 2022.10.02 |
---|---|
네트워크란?ERR_HTTP2_PROTOCOL_ERROR 정보 (0) | 2022.10.02 |
Java에서는 16진수까지의 정수 (0) | 2022.10.02 |
스프링 컨테이너의 싱글톤 디자인 패턴 vs 싱글톤 원두 (0) | 2022.10.02 |
Eclipse를 사용하여 Spring Boot 응용 프로그램을 디버깅하는 방법 (0) | 2022.10.02 |