N 열에 대한 규칙을 확인하는 좋은 방법이 있습니까?
-
09-09-2019 - |
문제
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 함수를 실행하는 오버 헤드가 있습니다. 더 빠른 규칙 수, 각 행의 열에 몇 개의 열 수 및 사용 된 인덱스에 따라 다릅니다.
더 읽기 쉬운 지 여부는 의견의 문제입니다.