MYSQL OR 대 IN 성능


180

다음과 같은 성능과 관련하여 차이가 있는지 궁금합니다.

SELECT ... FROM ... WHERE someFIELD IN(1,2,3,4)

SELECT ... FROM ... WHERE someFIELD between  0 AND 5

SELECT ... FROM ... WHERE someFIELD = 1 OR someFIELD = 2 OR someFIELD = 3 ... 

또는 MySQL이 컴파일러가 코드를 최적화하는 것과 같은 방식으로 SQL을 최적화합니까?

편집 : 의견에 명시된 이유로 AND의를 (으)로 변경했습니다 OR.


IM 도이 문제를 연구하고 있지만 IN이 s I could say that it can also be converted to UNION쿼리 최적화를 위해 OR 을 대체하기 위해 권장되는 OR 행으로 변환 될 것이라는 일부 진술에 반대 합니다.
Jānis Gruzis

답변:


249

나는 이것을 확실히 알아야했기 때문에 두 방법을 모두 벤치마킹했다. 나는을 IN사용하는 것보다 훨씬 빠르다는 것을 알게 되었습니다 OR.

"의견"을주는 사람들을 믿지 마십시오. 과학은 테스트와 증거에 관한 것입니다.

나는 동등한 쿼리의 1000 배의 루프를 실행했다 (일관성을 위해 사용했다 sql_no_cache).

IN: 2.34969592094s

OR: 5.83781504631s

업데이트 :
(6 년 전과 같이 원래 테스트의 소스 코드가 없지만이 테스트와 동일한 범위의 결과를 반환합니다)

이를 테스트하기위한 샘플 코드를 요청하는 가장 간단한 사용 사례는 다음과 같습니다. 구문 단순화를 위해 Eloquent를 사용하면 원시 SQL에 해당하는 것이 동일하게 실행됩니다.

$t = microtime(true); 
for($i=0; $i<10000; $i++):
$q = DB::table('users')->where('id',1)
    ->orWhere('id',2)
    ->orWhere('id',3)
    ->orWhere('id',4)
    ->orWhere('id',5)
    ->orWhere('id',6)
    ->orWhere('id',7)
    ->orWhere('id',8)
    ->orWhere('id',9)
    ->orWhere('id',10)
    ->orWhere('id',11)
    ->orWhere('id',12)
    ->orWhere('id',13)
    ->orWhere('id',14)
    ->orWhere('id',15)
    ->orWhere('id',16)
    ->orWhere('id',17)
    ->orWhere('id',18)
    ->orWhere('id',19)
    ->orWhere('id',20)->get();
endfor;
$t2 = microtime(true); 
echo $t."\n".$t2."\n".($t2-$t)."\n";

1482080514.3635
1482080517.3713
3.0078368186951

$t = microtime(true); 
for($i=0; $i<10000; $i++): 
$q = DB::table('users')->whereIn('id',[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])->get(); 
endfor; 
$t2 = microtime(true); 
echo $t."\n".$t2."\n".($t2-$t)."\n";

1482080534.0185
1482080536.178
2.1595389842987


21
이 테스트에 어떤 인덱스가 사용 되었습니까?
eggyal

5
또한 쿼리를 최적화하고이 IN문이 OR. 보다 약 30 % 빠릅니다 .
Timo002

12
Do not believe people who give their "opinion"당신은 100 % 맞습니다, 스택 오버플로는 불행히도 가득합니다
elipoultorak

7
성능 이유 (MariaDB (MySQL의 새로운 프리 브랜치) 문서 인용) : => 열이 정수이면 정수 전달하십시오 .Returns 1 if expr is equal to any of the values in the IN list, else returns 0. If all values are constants, they are evaluated according to the type of expr and sorted. The search for the item then is done using a binary search. This means IN is very quick if the IN value list consists entirely of constants . Otherwise, type conversion takes place according to the rules described at Type Conversion, but applied to all the arguments.IN
jave.web

10
' 자신의 의견을 제시하는 사람들을 믿지 말라 '에 대한 추론 : 이러한 수치를 얻는 데 사용되는 스크립트, 표 및 색인을 포함하지 않고 성능 수치를 제공하면 검증 할 수 없게됩니다. 이와 같이, 수치는 "의견"만큼 우수하다.
Disillusioned

67

또한 미래의 Google 직원을 대상으로 테스트를 수행했습니다. 반환 된 결과의 총 개수는 10000 중에서 7264입니다.

SELECT * FROM item WHERE id = 1 OR id = 2 ... id = 10000

이 쿼리는 0.1239몇 초가 걸렸 습니다

SELECT * FROM item WHERE id IN (1,2,3,...10000)

이 쿼리는 0.0433몇 초가 걸렸 습니다

IN 보다 3 배 빠르다 OR


15
어떤 MySQL 엔진이었으며 두 쿼리 사이에서 MySQL 버퍼 및 OS 파일 캐시를 지우셨습니까?
dabest1

2
테스트는 좁은 사용 사례입니다. 쿼리는 데이터의 72 %를 반환하며 인덱스의 이점을 얻지 못할 수 있습니다.
Disillusioned

그 시간의 대부분은 쿼리를 소비하고 구문 분석하고 쿼리 계획하는 데 걸렸습니다. 10k OR 문 OR을 사용하려는 경우 가능한 한 가장 작은 표현을 사용하는 것이 가장 좋습니다.
감독

17

수락 된 답변은 이유를 설명하지 않습니다.

아래는 고성능 MySQL, 3 판에서 인용 한 것입니다.

많은 데이터베이스 서버에서 IN ()은 여러 OR 절의 동의어 일뿐입니다. 두 개는 논리적으로 동일하기 때문입니다. MySQL에서는 그렇지 않습니다. IN () 목록의 값을 정렬하고 빠른 이진 검색을 사용하여 값이 목록에 있는지 확인합니다. 이것은 목록의 크기가 O (Log n) 인 반면, 등가의 OR 절은 목록의 크기가 O (n)입니다 (즉, 큰 목록의 경우 훨씬 느림).


특정 데이터베이스 이유에 대한 환상적인 참조. 좋은!
Joshua Pinter

완벽하고 핵심
gaurav9620

16

BETWEEN이 다음과 같이 변환되어야하기 때문에 더 빠를 것이라고 생각합니다.

Field >= 0 AND Field <= 5

IN이 어쨌든 많은 OR 문으로 변환 될 것입니다. IN의 가치는 사용의 용이성입니다. (각 열 이름을 여러 번 입력해야하고 기존 논리와 함께 사용하기가 더 쉬워집니다. IN이 하나의 명령문이므로 AND / OR 우선 순위에 대해 걱정할 필요가 없습니다. OR 문이 많으면 괄호로 묶어 하나의 조건으로 평가되도록합니다.)

귀하의 질문에 대한 유일한 실제 답변은 귀하의 질문을 제출하는 것 입니다. 그런 다음 특정 상황에서 가장 잘 작동하는 것을 알 수 있습니다.


통계적으로 사이에 범위 인덱스를 트리거 할 수 있습니다. IN ()은이 권한이 없습니다. 그러나 그렇습니다. 해변은 옳습니다. 인덱스의 사용 여부와 어느 것을 알고 있는지 요청을 프로파일 링해야합니다. MySQL 옵티마이 저가 무엇을 선택할지 예측하기는 정말 어렵습니다.
Savageman

"어쨌든 IN이 여러 개의 OR 문으로 변환 될 것입니다." 이거 어디서 읽었 어? O (1) 조회를하기 위해 해시 맵에 넣을 것으로 기대합니다.
Ztyx

IN이 OR로 변환되는 것은 SQLServer가 SQL Server를 처리하는 방법입니다 (또는 적어도 변경되었습니다-지금은 몇 년 동안 사용하지 않았 음). MySQL이이를 수행한다는 증거를 찾지 못했습니다.
RichardAtHome

4
이 답변은 "1 <= film_id <= 5"로 변환됩니다. 다른 두 솔루션은 단일 범위 조건으로 접히지 않습니다. 여기이 사용 OPTIMIZER 추적을 보여주는 블로그 게시물이 있습니다 tocker.ca/2015/05/25/...
모건 Tocker

13

그것은 당신이하고있는 것에 달려 있습니다. 범위의 넓이, 데이터 유형은 무엇입니까 (예에서는 숫자 데이터 유형을 사용하지만 귀하의 질문은 많은 다른 데이터 유형에도 적용될 수 있음).

이것은 두 가지 방식으로 쿼리를 작성하려는 인스턴스입니다. 작동시키고 EXPLAIN을 사용하여 실행 차이를 파악하십시오.

나는 이것에 대한 구체적인 대답이 있다고 확신하지만 이것이 실제로 내 주어진 질문에 대한 답을 알아내는 방법입니다.

이것은 도움이 될 것입니다 : http://forge.mysql.com/wiki/Top10SQLPerformanceTips

감사합니다,
프랭크


2
선택한 답변이어야합니다.
Jon z

3
링크가 오래되었습니다-이것이 동등한 것 같습니까? wikis.oracle.com/pages/viewpage.action?pageId=27263381 (Oracle ;-P 덕분에)
ilasno

1
동등한 페이지에서 "인덱싱 된 필드를 선택할 때 IN (...)을 사용하지 마십시오. SELECT 쿼리의 성능이 저하됩니다." -왜 그런지 알아?
jorisw

URL이 만료되었습니다
Steve Jiang

7

sunseeker의 관찰에 대한 한 가지 설명은 MySQL이 실제로 정적 값이고 이진 검색을 사용하는 경우 IN 문의 값을 정렬하는 것입니다. 일반 OR 대안보다 효율적입니다. 어디에서 읽었는지 기억이 나지 않지만 sunseeker의 결과는 증거인 것 같습니다.


4

안전하다고 생각했을 때만 ...

당신의 가치는 eq_range_index_dive_limit무엇입니까? 특히, IN조항 에 더 많거나 적은 항목이 있습니까?

여기에는 벤치 마크가 포함되지 않지만 내부 작업에 약간의 관심이 있습니다. 도구를 사용하여 무슨 일이 일어나고 있는지 확인하십시오-Optimizer Trace.

쿼리 : SELECT * FROM canada WHERE id ...

으로 OR3 개 값의 추적의 일부는 다음과 같습니다

       "condition_processing": {
          "condition": "WHERE",
          "original_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(multiple equal(296172, `canada`.`id`) or multiple equal(295093, `canada`.`id`) or multiple equal(293626, `canada`.`id`))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "293626 <= id <= 293626",
                      "295093 <= id <= 295093",
                      "296172 <= id <= 296172"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

ICP가 어떻게 제공되고 있는지 주목하십시오 ORs. 이 의미OR으로 설정되지 않은 IN, 그리고 InnoDB는 한 무리의 수행됩니다 =ICP를 통해 테스트를. (MyISAM을 고려할 가치가 있다고 생각하지 않습니다.)

(이것은 Percona의 5.6.22-71.0-log이며 id보조 인덱스입니다.)

이제 몇 가지 값을 가진 IN ()

eq_range_index_dive_limit= 10; 8 개의 값이 있습니다.

        "condition_processing": {
          "condition": "WHERE",
          "original_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "293626 <= id <= 293626",
                      "295093 <= id <= 295093",
                      "295573 <= id <= 295573",
                      "295588 <= id <= 295588",
                      "295810 <= id <= 295810",
                      "296127 <= id <= 296127",
                      "296172 <= id <= 296172",
                      "297148 <= id <= 297148"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

IN바뀌지 않은 것 같습니다 OR.

참고 : 상수 값이 정렬되었습니다 . 이것은 두 가지 방법으로 유익 할 수 있습니다.

  • 더 적게 뛰어 다니면 모든 값에 도달하기 위해 더 나은 캐싱, 적은 I / O가있을 수 있습니다.
  • 두 개의 유사한 쿼리가 별도의 연결에서 발생하고 트랜잭션에있는 경우 목록이 겹치므로 교착 상태 대신 지연이 발생할 가능성이 높습니다.

마지막으로 값이 많은 IN ()

      {
        "condition_processing": {
          "condition": "WHERE",
          "original_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "291752 <= id <= 291752",
                      "291839 <= id <= 291839",
                      ...
                      "297196 <= id <= 297196",
                      "297201 <= id <= 297201"
                    ],
                    "index_dives_for_eq_ranges": false,
                    "rows": 111,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

참고 사항 : 부피가 커서 이것이 필요했습니다.

@@global.optimizer_trace_max_mem_size = 32222;

3

또는 가장 느립니다. IN 또는 BETWEEN이 더 빠른지 여부는 데이터에 따라 다르지만 BETWEEN이 인덱스에서 범위를 취할 수 있기 때문에 일반적으로 더 빠를 것으로 기대합니다 (someField가 색인화되었다고 가정).


3

다음은 MySQL 5.6 @SQLFiddle을 사용한 6 가지 쿼리에 대한 세부 정보입니다.

요약하면 6 개의 쿼리가 독립적으로 인덱싱 된 열을 다루고 데이터 유형 당 2 개의 쿼리가 사용되었습니다. IN () 또는 OR 사용 여부에 관계없이 모든 쿼리에서 인덱스를 사용했습니다.

        |   ORs      |   IN()
integer | uses index | uses index
date    | uses index | uses index
varchar | uses index | uses index

나는 단지 OR을 사용하여 인덱스를 사용할 수 없다는 진술을 발표하고 싶었습니다. 사실이 아닙니다. 다음 예에서 6 개의 조회로 OR을 사용하는 조회에서 색인을 사용할 수 있습니다.

또한 IN ()이 OR 세트의 구문 단축키라는 사실을 많은 사람들이 무시한 것 같습니다. IN () -v- OR을 사용하는 것 사이의 소규모 성능 차이는 극도로 (마침내) 한계입니다.

더 큰 규모의 IN ()은 확실히 더 편리하지만, 문턱은 일련의 OR 조건과 논리적으로 동일합니다. 각 쿼리마다 상황이 변경되므로 테이블에서 쿼리를 테스트하는 것이 항상 가장 좋습니다.

6 개의 Explain 계획 요약, 모두 "인덱스 조건 사용"(오른쪽 스크롤)

  Query               select_type    table    type    possible_keys      key      key_len   ref   rows   filtered           Extra          
                      ------------- --------- ------- --------------- ----------- --------- ----- ------ ---------- ----------------------- 
  Integers using OR   SIMPLE        mytable   range   aNum_idx        aNum_idx    4               10     100.00     Using index condition  
  Integers using IN   SIMPLE        mytable   range   aNum_idx        aNum_idx    4               10     100.00     Using index condition  
  Dates using OR      SIMPLE        mytable   range   aDate_idx       aDate_idx   6               7      100.00     Using index condition  
  Dates using IN      SIMPLE        mytable   range   aDate_idx       aDate_idx   6               7      100.00     Using index condition  
  Varchar using OR    SIMPLE        mytable   range   aName_idx       aName_idx   768             10     100.00     Using index condition  
  Varchar using IN    SIMPLE        mytable   range   aName_idx       aName_idx   768             10     100.00     Using index condition  

SQL 바이올린

MySQL 5.6 스키마 설정 :

CREATE TABLE `myTable` (
  `id` mediumint(8) unsigned NOT NULL auto_increment,
  `aName` varchar(255) default NULL,
  `aDate` datetime,
  `aNum`  mediumint(8),
  PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;

ALTER TABLE `myTable` ADD INDEX `aName_idx` (`aName`);
ALTER TABLE `myTable` ADD INDEX `aDate_idx` (`aDate`);
ALTER TABLE `myTable` ADD INDEX `aNum_idx` (`aNum`);

INSERT INTO `myTable` (`aName`,`aDate`)
 VALUES 
 ("Daniel","2017-09-19 01:22:31")
,("Quentin","2017-06-03 01:06:45")
,("Chester","2017-06-14 17:49:36")
,("Lev","2017-08-30 06:27:59")
,("Garrett","2018-10-04 02:40:37")
,("Lane","2017-01-22 17:11:21")
,("Chaim","2017-09-20 11:13:46")
,("Kieran","2018-03-10 18:37:26")
,("Cedric","2017-05-20 16:25:10")
,("Conan","2018-07-10 06:29:39")
,("Rudyard","2017-07-14 00:04:00")
,("Chadwick","2018-08-18 08:54:08")
,("Darius","2018-10-02 06:55:56")
,("Joseph","2017-06-19 13:20:33")
,("Wayne","2017-04-02 23:20:25")
,("Hall","2017-10-13 00:17:24")
,("Craig","2016-12-04 08:15:22")
,("Keane","2018-03-12 04:21:46")
,("Russell","2017-07-14 17:21:58")
,("Seth","2018-07-25 05:51:30")
,("Cole","2018-06-09 15:32:53")
,("Donovan","2017-08-12 05:21:35")
,("Damon","2017-06-27 03:44:19")
,("Brian","2017-02-01 23:35:20")
,("Harper","2017-08-25 04:29:27")
,("Chandler","2017-09-30 23:54:06")
,("Edward","2018-07-30 12:18:07")
,("Curran","2018-05-23 09:31:53")
,("Uriel","2017-05-08 03:31:43")
,("Honorato","2018-04-07 14:57:53")
,("Griffin","2017-01-07 23:35:31")
,("Hasad","2017-05-15 05:32:41")
,("Burke","2017-07-04 01:11:19")
,("Hyatt","2017-03-14 17:12:28")
,("Brenden","2017-10-17 05:16:14")
,("Ryan","2018-10-10 08:07:55")
,("Giacomo","2018-10-06 14:21:21")
,("James","2018-02-06 02:45:59")
,("Colt","2017-10-10 08:11:26")
,("Kermit","2017-09-18 16:57:16")
,("Drake","2018-05-20 22:08:36")
,("Berk","2017-04-16 17:39:32")
,("Alan","2018-09-01 05:33:05")
,("Deacon","2017-04-20 07:03:05")
,("Omar","2018-03-02 15:04:32")
,("Thaddeus","2017-09-19 04:07:54")
,("Troy","2016-12-13 04:24:08")
,("Rogan","2017-11-02 00:03:25")
,("Grant","2017-08-21 01:45:16")
,("Walker","2016-11-26 15:54:52")
,("Clarke","2017-07-20 02:26:56")
,("Clayton","2018-08-16 05:09:29")
,("Denton","2018-08-11 05:26:05")
,("Nicholas","2018-07-19 09:29:55")
,("Hashim","2018-08-10 20:38:06")
,("Todd","2016-10-25 01:01:36")
,("Xenos","2017-05-11 22:50:35")
,("Bert","2017-06-17 18:08:21")
,("Oleg","2018-01-03 13:10:32")
,("Hall","2018-06-04 01:53:45")
,("Evan","2017-01-16 01:04:25")
,("Mohammad","2016-11-18 05:42:52")
,("Armand","2016-12-18 06:57:57")
,("Kaseem","2018-06-12 23:09:57")
,("Colin","2017-06-29 05:25:52")
,("Arthur","2016-12-29 04:38:13")
,("Xander","2016-11-14 19:35:32")
,("Dante","2016-12-01 09:01:04")
,("Zahir","2018-02-17 14:44:53")
,("Raymond","2017-03-09 05:33:06")
,("Giacomo","2017-04-17 06:12:52")
,("Fulton","2017-06-04 00:41:57")
,("Chase","2018-01-14 03:03:57")
,("William","2017-05-08 09:44:59")
,("Fuller","2017-03-31 20:35:20")
,("Jarrod","2017-02-15 02:45:29")
,("Nissim","2018-03-11 14:19:25")
,("Chester","2017-11-05 00:14:27")
,("Perry","2017-12-24 11:58:04")
,("Theodore","2017-06-26 12:34:12")
,("Mason","2017-10-02 03:53:49")
,("Brenden","2018-10-08 10:09:47")
,("Jerome","2017-11-05 20:34:25")
,("Keaton","2018-08-18 00:55:56")
,("Tiger","2017-05-21 16:59:07")
,("Benjamin","2018-04-10 14:46:36")
,("John","2018-09-05 18:53:03")
,("Jakeem","2018-10-11 00:17:38")
,("Kenyon","2017-12-18 22:19:29")
,("Ferris","2017-03-29 06:59:13")
,("Hoyt","2017-01-03 03:48:56")
,("Fitzgerald","2017-07-27 11:27:52")
,("Forrest","2017-10-05 23:14:21")
,("Jordan","2017-01-11 03:48:09")
,("Lev","2017-05-25 08:03:39")
,("Chase","2017-06-18 19:09:23")
,("Ryder","2016-12-13 12:50:50")
,("Malik","2017-11-19 15:15:55")
,("Zeph","2018-04-04 11:22:12")
,("Amala","2017-01-29 07:52:17")
;

.

update MyTable
set aNum = id
;

쿼리 1 :

select 'aNum by OR' q, mytable.*
from mytable
where aNum = 12
OR aNum = 22
OR aNum = 27
OR aNum = 32
OR aNum = 42
OR aNum = 52
OR aNum = 62
OR aNum = 65
OR aNum = 72
OR aNum = 82

결과 :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| aNum by OR | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| aNum by OR | 22 |  Donovan | 2017-08-12T05:21:35Z |   22 |
| aNum by OR | 27 |   Edward | 2018-07-30T12:18:07Z |   27 |
| aNum by OR | 32 |    Hasad | 2017-05-15T05:32:41Z |   32 |
| aNum by OR | 42 |     Berk | 2017-04-16T17:39:32Z |   42 |
| aNum by OR | 52 |  Clayton | 2018-08-16T05:09:29Z |   52 |
| aNum by OR | 62 | Mohammad | 2016-11-18T05:42:52Z |   62 |
| aNum by OR | 65 |    Colin | 2017-06-29T05:25:52Z |   65 |
| aNum by OR | 72 |   Fulton | 2017-06-04T00:41:57Z |   72 |
| aNum by OR | 82 |  Brenden | 2018-10-08T10:09:47Z |   82 |

쿼리 2 :

select 'aNum by IN' q, mytable.*
from mytable
where aNum IN (
            12
          , 22
          , 27
          , 32
          , 42
          , 52
          , 62
          , 65
          , 72
          , 82
          )

결과 :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| aNum by IN | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| aNum by IN | 22 |  Donovan | 2017-08-12T05:21:35Z |   22 |
| aNum by IN | 27 |   Edward | 2018-07-30T12:18:07Z |   27 |
| aNum by IN | 32 |    Hasad | 2017-05-15T05:32:41Z |   32 |
| aNum by IN | 42 |     Berk | 2017-04-16T17:39:32Z |   42 |
| aNum by IN | 52 |  Clayton | 2018-08-16T05:09:29Z |   52 |
| aNum by IN | 62 | Mohammad | 2016-11-18T05:42:52Z |   62 |
| aNum by IN | 65 |    Colin | 2017-06-29T05:25:52Z |   65 |
| aNum by IN | 72 |   Fulton | 2017-06-04T00:41:57Z |   72 |
| aNum by IN | 82 |  Brenden | 2018-10-08T10:09:47Z |   82 |

쿼리 3 :

select 'adate by OR' q, mytable.*
from mytable
where aDate= str_to_date("2017-02-15 02:45:29",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-03-10 18:37:26",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-05-20 16:25:10",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-07-10 06:29:39",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-07-14 00:04:00",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-08-18 08:54:08",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-10-02 06:55:56",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-04-20 07:03:05",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-03-02 15:04:32",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-09-19 04:07:54",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2016-12-13 04:24:08",'%Y-%m-%d %h:%i:%s')

결과 :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| adate by OR | 47 |     Troy | 2016-12-13T04:24:08Z |   47 |
| adate by OR | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
| adate by OR | 44 |   Deacon | 2017-04-20T07:03:05Z |   44 |
| adate by OR | 46 | Thaddeus | 2017-09-19T04:07:54Z |   46 |
| adate by OR | 10 |    Conan | 2018-07-10T06:29:39Z |   10 |
| adate by OR | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| adate by OR | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |

쿼리 4 :

select 'adate by IN' q, mytable.*
from mytable
where aDate IN (
          str_to_date("2017-02-15 02:45:29",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-03-10 18:37:26",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-05-20 16:25:10",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-07-10 06:29:39",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-07-14 00:04:00",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-08-18 08:54:08",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-10-02 06:55:56",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-04-20 07:03:05",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-03-02 15:04:32",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-09-19 04:07:54",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2016-12-13 04:24:08",'%Y-%m-%d %h:%i:%s')
        )

결과 :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| adate by IN | 47 |     Troy | 2016-12-13T04:24:08Z |   47 |
| adate by IN | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
| adate by IN | 44 |   Deacon | 2017-04-20T07:03:05Z |   44 |
| adate by IN | 46 | Thaddeus | 2017-09-19T04:07:54Z |   46 |
| adate by IN | 10 |    Conan | 2018-07-10T06:29:39Z |   10 |
| adate by IN | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| adate by IN | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |

쿼리 5 :

select 'name by  OR' q, mytable.*
from mytable
where aname = 'Alan'
OR aname = 'Brian'
OR aname = 'Chandler'
OR aname = 'Darius'
OR aname = 'Evan'
OR aname = 'Ferris'
OR aname = 'Giacomo'
OR aname = 'Hall'
OR aname = 'James'
OR aname = 'Jarrod'

결과 :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| name by  OR | 43 |     Alan | 2018-09-01T05:33:05Z |   43 |
| name by  OR | 24 |    Brian | 2017-02-01T23:35:20Z |   24 |
| name by  OR | 26 | Chandler | 2017-09-30T23:54:06Z |   26 |
| name by  OR | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |
| name by  OR | 61 |     Evan | 2017-01-16T01:04:25Z |   61 |
| name by  OR | 90 |   Ferris | 2017-03-29T06:59:13Z |   90 |
| name by  OR | 37 |  Giacomo | 2018-10-06T14:21:21Z |   37 |
| name by  OR | 71 |  Giacomo | 2017-04-17T06:12:52Z |   71 |
| name by  OR | 16 |     Hall | 2017-10-13T00:17:24Z |   16 |
| name by  OR | 60 |     Hall | 2018-06-04T01:53:45Z |   60 |
| name by  OR | 38 |    James | 2018-02-06T02:45:59Z |   38 |
| name by  OR | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |

쿼리 6 :

select 'name by IN' q, mytable.*
from mytable
where aname IN (
      'Alan'
     ,'Brian'
     ,'Chandler'
     , 'Darius'
     , 'Evan'
     , 'Ferris'
     , 'Giacomo'
     , 'Hall'
     , 'James'
     , 'Jarrod'
     )

결과 :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| name by IN | 43 |     Alan | 2018-09-01T05:33:05Z |   43 |
| name by IN | 24 |    Brian | 2017-02-01T23:35:20Z |   24 |
| name by IN | 26 | Chandler | 2017-09-30T23:54:06Z |   26 |
| name by IN | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |
| name by IN | 61 |     Evan | 2017-01-16T01:04:25Z |   61 |
| name by IN | 90 |   Ferris | 2017-03-29T06:59:13Z |   90 |
| name by IN | 37 |  Giacomo | 2018-10-06T14:21:21Z |   37 |
| name by IN | 71 |  Giacomo | 2017-04-17T06:12:52Z |   71 |
| name by IN | 16 |     Hall | 2017-10-13T00:17:24Z |   16 |
| name by IN | 60 |     Hall | 2018-06-04T01:53:45Z |   60 |
| name by IN | 38 |    James | 2018-02-06T02:45:59Z |   38 |
| name by IN | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |

2

나는 그들이 똑같을 것이라고, 다음을 수행하여 테스트를 실행할 수 있습니다.

"in (1,2,3,4)"를 500 번 반복하고 시간이 얼마나 걸리는지보십시오. "= 1 또는 = 2 or = 3 ..."버전을 500 번 반복하여 얼마나 오래 실행되는지 확인하십시오.

someField가 인덱스이고 테이블이 크면 조인 방법을 사용해 볼 수도 있습니다.

SELECT ... 
    FROM ... 
        INNER JOIN (SELECT 1 as newField UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) dt ON someFIELD =newField

위의 SQL Server에서 조인 방법을 시도했지만 in (1,2,3,4)와 거의 동일하며 둘 다 클러스터 인덱스 검색을 수행합니다. MySQL이 어떻게 처리 할 지 잘 모르겠습니다.



0

컴파일러가 이러한 유형의 쿼리를 최적화하는 방식에 대해 이해 한 것에서 IN 절을 사용하는 것이 여러 OR 절보다 효율적입니다. BETWEEN 절을 사용할 수있는 값이 있으면 더 효율적입니다.


0

Field에 대한 색인이있는 한 BETWEEN 은이를 사용하여 한쪽 끝을 빨리 찾은 다음 다른 쪽 끝을 가로 지 릅니다. 이것이 가장 효율적입니다.

내가 본 모든 EXPLAIN은 "IN (...)"과 "... OR ..."이 상호 교환 가능하고 똑같이 (비효율적 임) 보여줍니다. 옵티마이 저가 간격을 구성하는지 여부를 알 수있는 방법이 없기 때문에 예상 한 것입니다. 개별 값의 UNION ALL SELECT와 동일합니다.


0

다른 사람들이 설명했듯이 IN은 쿼리 성능과 관련하여 OR보다 선택하는 것이 좋습니다.

다음과 같은 경우 OR 조건의 쿼리는 실행 시간이 더 오래 걸릴 수 있습니다.

  1. MySQL 옵티마이 저가 다른 인덱스를 효율적으로 선택하면 실행됩니다 (거짓 긍정적 인 경우).
  2. 기록 수가 더 많은 경우 (Jacob에 의해 명확하게 언급 된대로)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.