문제

3 열 A, B 및 C가있는 테이블 규칙이 있다고 가정 해 봅시다. 데이터가 시스템에 들어가면 규칙 테이블의 행이 규칙 테이블의 해당 열이 NULL 인 경우 조건과 내 데이터와 일치하는지 알고 싶습니다. , 모든 데이터와 일치합니다. 명백한 SQL은 다음과 같습니다.

SELECT * FROM RULES
WHERE (A = :a OR A IS NULL)
  AND (B = :b OR B IS NULL)
  AND (C = :c OR C IS NULL)

그래서 규칙이 있다면 :

RULE    A        B        C
1       50       NULL     NULL
2       51       xyz      NULL
3       51       NULL     123
4       NULL     xyz      456

(50, XYZ, 456)의 입력은 규칙 1과 4와 일치합니다.

의문: 더 좋은 방법이 있습니까? 3 개의 필드 만 있으면 문제가되지 않습니다. 그러나 실제 테이블에는 15 개의 열이 있으며 SQL 스케일이 얼마나 잘 있는지 걱정합니다.

추측: 내가 생각해 낸 대체 SQL 문은 얼마나 많은 필드가 널이 아닌지에 대한 계수로 테이블에 추가 열을 추가하는 것과 관련이 있습니다. (예에서는 규칙 1-4 의이 열 값이 각각 1, 2, 2 및 2입니다.)이 "col_count"열에서 선택은 다음과 같습니다.

SELECT * FROM RULES
WHERE (CASE WHEN A = :a THEN 1 ELSE 0 END)
    + (CASE WHEN B = :b THEN 1 ELSE 0 END)
    + (CASE WHEN C = :c THEN 1 ELSE 0 END)
    = COL_COUNT

불행히도, 나는 우리의 어떤 접근법이 더 잘 수행 될지 알기에 충분한 샘플 데이터가 없습니다. 무작위 규칙을 만들기 전에 여기에서 더 나은 접근 방식이 있는지 물어볼 것이라고 생각했습니다.

메모: 데이터 마이닝 기술 및 열 제약 조건은 여기서는 가능하지 않습니다. 데이터는 시스템에 들어가면 확인해야하므로 즉시 통과/실패로 표시 될 수 있습니다. 또한 사용자는 규칙의 추가 또는 제거를 제어하여 규칙을 열 제약 조건 또는 기타 데이터 정의 문으로 변환 할 수 없습니다.

마지막으로, 결국 데이터가 전달되지 않은 모든 규칙의 목록이 필요합니다. 솔루션은 첫 번째 실패시 중단 될 수 없습니다.

감사.

도움이 되었습니까?

해결책

제공 한 첫 번째 쿼리는 완벽합니다. 나는 당신이 말하는 열을 추가하면 모든 항목의 null 속성이없는 속성이 어쨌든 확인되기 때문에 더 빠른 속도를 줄 것입니다. 그래서 나는 그것을 추측 할 것입니다 x=y 확장됩니다 x IS NOT NULL AND x=y 내부적. 어쩌면 다른 사람이 그것을 명확히 할 수 있습니다.

내가 생각할 수있는 다른 모든 최적화에는 사전 계산 또는 캐싱이 포함됩니다. 특정 규칙과 일치하는 [임시] 테이블을 만들거나 일치하는 규칙을 보유하는 열을 추가 할 수 있습니다.

다른 팁

행/규칙이 너무 많습니까? 그렇지 않은 경우 (주관적이지만 10,000 미만이라고 말하면) 모든 열에 대한 색인을 만들 수 있습니다.

이는 속도를 크게 높이고 색인은 많은 공간을 차지하지 않습니다.

거대한 규칙 테이블을 만들 계획이 없다면 모든 열을 색인하면 접근 방식이 정상이라고 확신합니다.

값으로 규칙 테이블의 지수를 만들지 않겠습니까? 그럼 당신은 할 수 있습니다

SELECT myvalue FROM RULES_A

당신이 실제로 가지고있는 것은 규칙과 규칙 세트 인 것 같습니다. 이를 모델링하면이 특정 코딩을 훨씬 간단하게 만들뿐만 아니라 16 개의 열이 필요하다고 결정할 때 모델을 확장 할 수 있습니다.

예를 들어:

CREATE TABLE Rules (
    rule_id         INT         NOT NULL,
    rule_category   CHAR(1)     NOT NULL, -- This is like your column idea
    rule_int_value  INT         NULL,
    rule_str_value  VARCHAR(20) NULL,
    CONSTRAINT PK_Rules PRIMARY KEY CLUSTERED (rule_id),
    CONSTRAINT CK_Rules_one_value CHECK (rule_int_value IS NULL OR rule_str_value IS NULL)
)

CREATE TABLE Rule_Sets (
    rule_set_id INT NOT NULL,
    rule_id     INT NOT NULL,
    CONSTRAINT PK_Rule_Sets PRIMARY KEY CLUSTERED (rule_set_id, rule_id)
)

주어진 규칙과 일치하는 일부 데이터 :

INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (1, 'A', 50, NULL)
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (2, 'A', 51, NULL)
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (3, 'B', NULL, 'xyz')
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (4, 'C', 123, NULL)
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (5, 'C', 456, NULL)

INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (1, 1)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (2, 2)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (2, 3)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (3, 2)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (3, 4)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (4, 3)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (4, 5)

당신이 기대하는 것과 동일한 답을 확인하는 테스트 스크립트 :

DECLARE
    @a  INT,
    @b  VARCHAR(20),
    @c  INT

SET @a = 50
SET @b = 'xyz'
SET @c = 456

SELECT DISTINCT
    rule_set_id AS failed_rule_set_id
FROM
    Rule_Sets RS
WHERE
    NOT EXISTS (SELECT * FROM Rules R WHERE R.rule_id = RS.rule_id AND @a = R.rule_int_value) AND
    NOT EXISTS (SELECT * FROM Rules R WHERE R.rule_id = RS.rule_id AND @b = R.rule_str_value) AND
    NOT EXISTS (SELECT * FROM Rules R WHERE R.rule_id = RS.rule_id AND @c = R.rule_int_value)

개별 매개 변수가 아닌 세트 기반 형식으로 입력 데이터를 제시 할 수 있다면 최종 SQL 문은 더 역동적 일 수 있으며 추가 열을 추가 할 때 성장할 필요가 없습니다.

SELECT * FROM RULES
 WHERE (A = :a OR A IS NULL)
   AND (B = :b OR B IS NULL)
   AND (C = :c OR C IS NULL);

RBDM에 따라, 이것은별로 그렇지는 않지만 더 효율적이지 않을 수도 있습니다.

SELECT * FROM RULES
 WHERE coalesce(A, :a) = :a
   AND coalesce(B, :b) = :b 
   AND coalesce(C, :c) = :c ;

MySQL에서 (RBDMS 가이 작업을 다르게 수행 할 수 있음),이 쿼리는 index a보다는 스캔 ref_or_null 적용 가능한 색인이있는 경우 스캔하십시오. 인덱스가 모든 열을 다루는 경우 전체 인덱스를 사용할 수 있습니다 (실제로 인덱스가 모든 열을 포함하는 경우 색인 ~이다 탁자).

쿼리와 함께 a ref_or_null 액세스는 대신 수행됩니다 index 액세스 및 다중 열 인덱스의 첫 번째 열만 사용됩니다. 와 함께 ref_or_null, MySQL은 인덱스를 일치에 대해 검색 한 다음 NULLS를 다시 검색해야합니다. 따라서 인덱스를 두 번 사용하지만 전체 색인을 사용하지 않습니다.

그러나 Coalesce를 사용하면 각 열 값에서 Coalesce 함수를 실행하는 오버 헤드가 있습니다. 더 빠른 규칙 수, 각 행의 열에 몇 개의 열 수 및 사용 된 인덱스에 따라 다릅니다.

더 읽기 쉬운 지 여부는 의견의 문제입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top