MySQL OR과 IN의 퍼포먼스 비교
퍼포먼스에 대해서 다음 사이에 차이가 있는지 궁금합니다.
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
는 코멘트에 기재되어 있는 이유에 의한 것입니다.
나는 이것을 확실히 알아야 했기 때문에 두 가지 방법을 모두 벤치마킹했다.나는 일관되게 찾았다.IN
하는 보다 훨씬 OR
.
"의견"을 제시하는 사람들을 믿지 마세요. 과학은 실험과 증거의 전부입니다.
쿼리 유지하기 1000배의 했습니다).sql_no_cache
IN
: 2.34969592094s
OR
: 5.83781504631s
업데이트:
(6년 전과 같이 원래 테스트의 소스 코드는 없지만, 이 테스트와 같은 범위의 결과가 반환됩니다.)
이를 테스트하기 위한 샘플코드를 요청하기 위해 가능한 가장 간단한 사용 예를 다음에 제시하겠습니다.구문을 단순화하기 위해 Armanent를 사용하면 raw 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
나는 미래의 구글러들을 위한 테스트도 했다.반환된 결과의 총 수는 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
OR
인정된 답변으로는 이유가 설명되지 않습니다.
High Performance MySQL, 3rd Edition에서 인용한 내용은 다음과 같습니다.
많은 데이터베이스 서버에서 IN()은 논리적으로 동일한 여러 OR 구와 동의어일 뿐입니다.MySQL에서는 그렇지 않습니다.MySQL에서는 IN() 목록의 값을 정렬하고 고속 바이너리 검색을 사용하여 값이 목록에 있는지 확인합니다.이것은 리스트 사이즈에서는 O(Log n)이지만, 동등한 일련의 OR 구는 리스트 사이즈에서는 O(n)입니다(즉, 큰 리스트에서는 훨씬 느립니다).
BETWEEN은 다음과 같이 변환되어야 하므로 더 빠를 것으로 생각합니다.
Field >= 0 AND Field <= 5
어쨌든 IN은 여러 OR 문장으로 변환될 것으로 알고 있습니다.IN의 가치는 사용의 용이성입니다.(각 열 이름을 여러 번 입력할 필요가 없어지고 기존 로직에서도 사용하기 쉬워집니다.IN은 하나의 문장이기 때문에 AND/OR 우선순위를 걱정할 필요가 없습니다.여러 OR 문장의 경우 괄호로 둘러싸서 하나의 조건으로 평가되도록 해야 합니다.)
당신의 질문에 대한 유일한 진정한 대답은 당신의 질의에 대한 프로파일링입니다.그러면 특정 상황에서 가장 잘 작동하는 것이 무엇인지 알 수 있습니다.
작업 내용, 범위, 데이터 유형에 따라 달라집니다(예에서 숫자 데이터 유형을 사용하는 것은 알지만 질문은 다양한 데이터 유형에도 적용될 수 있습니다).
이는 쿼리를 양방향으로 쓰는 경우입니다. 쿼리를 작동시킨 후 EXPLY를 사용하여 실행 차이를 계산합니다.
이에 대한 구체적인 답변이 있을 것이라고 확신합니다만, 실제로 이렇게 말하면, 저는 주어진 질문에 대한 답을 알아낼 수 있습니다.
이것은 도움이 될 수 있습니다.http://forge.mysql.com/wiki/Top10SQLPerformanceTips
★★★★★★★★★★★★★★★★,
★★★★★★★★★★★★★★★★★.
Sunseeker의 관찰에 대한 설명 중 하나는 MySQL이 모두 정적 값이고 바이너리 검색을 사용하는 경우 IN 문의 값을 정렬한다는 것입니다. 이는 일반 OR 대안보다 더 효율적입니다.어디서 읽었는지 기억이 안 나는데, 선시커의 결과가 증거인 것 같아요.
안전하다고 생각했을 때...
의의의 는 어느 입니까?eq_range_index_dive_limit
특히, 고객님이 가지고 계신 아이템의 수가 많거나 적거나IN
조??
여기에는 벤치마크는 포함되지 않지만 내부 작업을 조금 들여다 볼 수 있습니다.Optimizer Trace(최적화 트레이스)라는 툴을 사용하여 상황을 확인합니다.
SELECT * FROM canada WHERE id ...
값이 3개인 경우 트레이스의 일부는 다음과 같습니다.
"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)입니다.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;
OR은 가장 느립니다.IN과 BETWEEN 중 어느 쪽이 빠른지는 데이터에 따라 다르지만, 인덱스(일부 필드가 색인화되었다고 가정할 때)의 범위가 단순하기 때문에 BETWEEN은 일반적으로 더 빠를 것으로 예상됩니다.
다음은 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
난 그저 수술실에서 인덱스를 사용할 수 없다는 진술을 폭로하고 싶었을 뿐이야그건 사실이 아니야.인덱스는 다음 예제의 6개 쿼리와 같이 OR을 사용하여 쿼리에서 사용할 수 있습니다.
또한 IN()이 일련의 OR에 대한 구문 단축키라는 사실을 무시하는 사람이 많은 것 같습니다.소규모에서는 IN() -v-OR을 사용하는 경우의 성능 차이는 극히(무제한) 미미한 수준입니다.
대규모에서는 IN()이 확실히 편리하지만 논리적으로는 일련의 OR 조건과 동일합니다.각 쿼리의 상황이 변경되므로 테이블에서 쿼리를 테스트하는 것이 항상 가장 좋습니다.
6가지 설명 계획 요약, 모두 "인덱스 조건 사용" (오른쪽 스크롤)
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
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 |
2018: IN(...)이 더 빠릅니다.그러나 >= & <=는 IN보다 더 빠릅니다.
제 벤치마크는 이렇습니다.
이 두 가지가 동일할 것입니다.다음 절차를 수행하여 테스트를 실행할 수 있습니다.
입력(1,2,3,4)을 500회 반복하여 소요시간을 확인합니다."=1 또는 =2 또는=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에서 시도해보니 (1, 2, 3, 4)와 거의 비슷하며 둘 다 클러스터화된 인덱스 시크가 발생합니다.MySQL이 어떻게 처리할지 모르겠어요.
다른 사람이 설명하듯이 쿼리 성능에 관해서는 OR보다 IN을 선택하는 것이 좋습니다.
OR 조건을 가진 쿼리는 다음과 같은 경우 실행 시간이 더 오래 걸릴 수 있습니다.
- MySQL optimizer가 다른 인덱스를 효율적으로 선택한 경우(false positive case 동안).
- 기록 수가 더 많은 경우(Jacob에 의해 명확하게 진술됨)
컴파일러가 이러한 유형의 쿼리를 최적화하는 방법에 대해 알고 있는 바로는 IN 절을 사용하는 것이 여러 OR 절보다 효율적입니다.BETHWEN 절을 사용할 수 있는 값이 있는 경우 더 효율적입니다.
필드에 인덱스가 있는 한 BETWEEN은 이 인덱스를 사용하여 한 쪽 끝을 빠르게 찾은 다음 다른 쪽 끝을 탐색합니다.이것이 가장 효율적입니다.
내가 본 모든 EXPLY는 "IN (...)"과 "..."을 나타낸다.교환이 가능하고 (비효율적)이 같아야 합니다.옵티마이저는 그것들이 간격을 구성하는지 여부를 알 수 없기 때문에 예상할 수 있습니다.또한 개별 값에 대한 UNION ALL SELECT와 동일합니다.
언급URL : https://stackoverflow.com/questions/782915/mysql-or-vs-in-performance
'source' 카테고리의 다른 글
유형 힌트를 사용하여 "nullable" 반환 유형을 지정하는 방법 (0) | 2022.12.25 |
---|---|
Java 생성자에서 int 배열 초기화 (0) | 2022.12.25 |
Eclipse는 왜 @Override on interface methods에 대해 불평하는가? (0) | 2022.12.25 |
Java에는 사용 설명서가 있습니까? (0) | 2022.12.25 |
근거가 약한 레퍼런스에 대한 실용적인 용도가 있습니까? (0) | 2022.11.25 |