>  기사  >  데이터 베이스  >  MySQL은 OR 조건을 사용하여 인덱스 열을 피합니다.

MySQL은 OR 조건을 사용하여 인덱스 열을 피합니다.

黄舟
黄舟원래의
2017-02-21 10:31:111270검색



개발 전 SQL 코드에서는 where 조건이 업데이트된 쿼리도 여러 번 있었습니다. 다음은 or 사용의 단점과 이를 개선하는 방법을 보여주는 예입니다.

select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and (f_mobile ='1234567891' or f_phone ='1234567891' ) limit 1

f_mobile과 f_phone 필드 모두 전화번호를 저장할 수 있다는 것을 쿼리문에서 쉽게 알 수 있습니다. 일반적인 아이디어는 이를 SQL로 사용하거나 해결하는 것이지만, 많은 양의 테이블 데이터는 단순히 재해:

MySQL은 OR 조건을 사용하여 인덱스 열을 피합니다.

t_tbanme1에는 idx_id_mobile(f_xxx_id,f_mobile), idx_phone(f_phone), idx_id_email(f_id,f_email) 인덱스가 있지만 설명 결과는 idx_id_email 인덱스를 사용합니다. . 때로는 운이 좋게도 idx_id_mobile f_xxx_id

를 사용할 수 있습니다. 왜냐하면 mysql의 각 쿼리에 대해 각 테이블에서 하나의 인덱스만 선택할 수 있기 때문입니다. idx_id_mobile 인덱스를 사용했는데 제한이 1이어서 데이터가 한 개만 있는 경우에는 빨리 결과를 얻을 수 있기를 바랍니다. 그러나 f_mobile에 대한 데이터가 없으면 f_phone 필드는 아래에서 하나씩만 검색할 수 있습니다. f_id 조건, 120,000개의 행을 스캔합니다. 또는 and와는 다릅니다. (f_xxx_id,f_mobile,f_phone)을 추가하면 피가 토할 것 같다고 생각하는 개발자도 있습니다~

95712e0b0bc62c64b1fddfac486f9cb8

따라서 SQL 최적화는 매우 간단합니다(f_mobile 및 f_phone에 해당 인덱스가 있어야 함), 방법 1:

(select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_mobile ='1234567891' limit 1 ) UNION ALL 
(select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_phone ='1234567891' limit 1 )

MySQL은 OR 조건을 사용하여 인덱스 열을 피합니다.

두 개의 독립적인 SQL이 인덱스를 사용할 수 있으며 각 쿼리에는 자체 제한이 있습니다. 두 결과 집합이 모두 반환되면 하나만 선택하세요.

이런 쿼리가 특히 자주 발생하는 경우(그리고 캐시가 없는 경우) 별도의 SQL 실행으로 변경하는 방법도 있습니다. 예를 들어 대부분의 숫자 값이 켜져 있습니다. f_mobile을 실행한 후 sql1을 먼저 실행하면 결과가 나올 것이고, 결과가 없다고 판단한 후 sql2를 실행하면 데이터베이스 쿼리 속도가 느려지고 코드에서 더 많은 작업을 처리할 수 있습니다. 의사 코드:

sql1 = select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_mobile ='1234567891' limit 1;
sq1.execute();
if no result sql1:
  sql1 = select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_phone ='1234567891' limit 1;
    sql1.execute();

이것은 더 복잡한 시나리오를 위한 것입니다. 레코드를 반환하는 것만큼 간단합니다. 제한 2:

select a.f_crm_id from d_dbname1.t_tbname1 as a where (a.f_create_time > from_unixtime('1464397527') or a.f_modify_time > from_unixtime('1464397527') ) limit 0,200

이 경우 방법 1과 2가 필요합니다. f_create_time과 f_modify_time 모두 판단 조건을 만족할 수 있으므로 중복된 데이터가 반환됩니다.

방법 1을 수정해야 합니다:

(select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_create_time > from_unixtime('1464397527') limit 0,200 ) UNION ALL
(select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_modify_time > from_unixtime(&#39;1464397527&#39;)and a.f_create_time <= from_unixtime(&#39;1464397527&#39;) limit 0,200)

UNION ALL을 UNION으로 변경해도 중복이 제거되지 않는다고 누가 말했습니까? 쿼리가 빈번하거나 제한이 상대적으로 큰 경우 데이터베이스는 여전히 압박을 받고 있으므로 절충이 필요합니다.

제한 주문이 필요한 상황을 포함하여 이 경우 방법 2가 더 적합합니다. 의사 코드 수정:

sql1 = (select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_create_time > from_unixtime(&#39;1464397527&#39;) limit 0,200 );
sql1.execute();
sql1_count = sql1.result.count
if sql1_count < 200 :
  sql2 = (select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_modify_time > from_unixtime(&#39;1464397527&#39;) 
  and a.f_create_time <= from_unixtime(&#39;1464397527&#39;) limit 0, (200 - sql1_count) );
  sql2.execute();

final_result = paste(sql1,sql2);

또는 데이터베이스에서 조건을 최적화하기 어렵습니다. 데이터베이스가 중단되지 않도록 코드에서 논리를 최적화할 수 있습니다. or 조건에서 인덱스가 필요하지 않은 경우(비교할 데이터의 양이 적은 경우)에만 고려됩니다.

동일한 필드 또는 f_id=1 또는 f_id=100 -> f_id in (1,100) 과 같이 in으로 변경될 수 있습니다. 효율성 문제에 대해서는 mysql에서 또는 및 in의 효율성 문제 문서를 참조하세요.

위의 최적화 시나리오는 모두 InnoDB의 경우 스토리지 엔진입니다. MyISAM에서는 전체 테이블을 피하기 위해 인덱스를 사용할 수 있는 조건이 다릅니다.

위 내용은 MySQL에서 인덱스 컬럼에 OR 조건을 사용하지 않도록 하는 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.