MySQL Views ИЛИ против IN предложения - PullRequest
5 голосов
/ 22 февраля 2012

MySQL Server version: 5.1.41 В Ubuntu 10.04

Я столкнулся с различием в поведении MySQL при изменении некоторых запросов и хотел узнать причину этого.

В основном я создаю представление. Когда я запрашиваю представление, набор результатов такой же Однако число прочитанных строк для предложения IN отличается от предложения OR. Ниже приведен простой пример:

CREATE TABLE country ( 
    id_country int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(50) NOT NULL, 
    PRIMARY KEY (id_country) 
) ENGINE=InnoDB; 

INSERT INTO country (name) VALUES ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'); 

CREATE TABLE status ( 
    id_status int(11) NOT NULL AUTO_INCREMENT, 
    id_country int(11) NOT NULL, 
    status tinyint(4) NOT NULL, 
    PRIMARY KEY (id_status) 
) ENGINE=InnoDB; 
ALTER TABLE status ADD INDEX ( id_country ); 
ALTER TABLE status ADD FOREIGN KEY ( id_country ) REFERENCES test.country (id_country) ON DELETE RESTRICT ON UPDATE RESTRICT ; 

INSERT INTO status(id_country, status) VALUES 
(1,0), (2,1), (3,0), (4,1), (5,0),(6,1), (7,0), (8,1); 

CREATE ALGORITHM=MERGE VIEW view_country 
AS 
    SELECT c.*, s.id_status, s.status 
    FROM country c JOIN status s ON c.id_country = s.id_country; 

2 приведенных ниже оператора объяснения показывают разное количество проанализированных строк

mysql> EXPLAIN EXTENDED  SELECT * FROM view_country WHERE id_country IN (1, 2, 3)\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: c
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: s
         type: ref
possible_keys: id_country
          key: id_country
      key_len: 4
          ref: test.c.id_country
         rows: 1
     filtered: 100.00
        Extra: 
2 rows in set, 1 warning (0.00 sec)

Использование оператора OR

mysql> EXPLAIN EXTENDED SELECT * FROM view_country WHERE id_country = 1 OR id_country = 2 OR id_country = 3\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: s
         type: ALL
possible_keys: id_country
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 8
     filtered: 37.50
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: c
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: test.s.id_country
         rows: 1
     filtered: 100.00
        Extra: 
2 rows in set, 1 warning (0.00 sec)

Если вы посмотрите на «строки» в обоих запросах - они складываются по-разному

Запрос с предложением OR читает меньше строк по сравнению с IN, что складывается для огромных таблиц и объединений.

Может кто-нибудь помочь мне понять, почему это так?

Спасибо за ваше время.

Ответы [ 2 ]

1 голос
/ 24 февраля 2012

Обратите внимание, что планы выполнения имеют непосредственное отношение к состоянию ваших индексов и размеру ваших таблиц. MySQL может работать по-разному даже для похожих запросов, а иногда MySQL может даже догадываться неправильно.

Вид с помощью JOIN определенно усложняет ситуацию, поэтому ваш оператор SELECT не так прост. Не удивляйтесь, что MySQL выбирает другой план выполнения для IN и OR.

В случае первого запроса MySQL решил использовать индексы для обоих запросов, что приводит к определенному и точному количеству строк в EXPLAIN.

Однако во втором запросе MySQL решил сканировать все строки в таблице состояния. Это имеет смысл, так как строк так мало, и MySQL все равно должен посещать таблицу, потому что нет покрывающего индекса, который бы возвращал все необходимые строки. Я не удивлюсь, если второй запрос на самом деле не быстрее первого. Также обратите внимание, что количество строк (для сканирования) в EXPLAIN является оценочным, поэтому учитывайте это при профилировании ваших запросов.

Первый запрос должен выполнить 6 поисков, тогда как второй запрос должен выполнить только 3 поиска после очень короткого сканирования таблицы.

Существует множество хитростей, которые MySQL делает, которые иногда ограничиваются очень конкретными сценариями, чтобы попытаться оптимизировать ваш запрос на основе текущих индексов и количества строк. Существуют документированные случаи, когда для похожих запросов MySQL будет использовать два разных подхода и в итоге получит один и тот же путь выполнения . Существуют и другие случаи, когда два совершенно разных плана выполнения приводят к одинаковой производительности, и это один из таких случаев.

В любом случае, я надеюсь, что это объясняет вам, почему есть разница, но пока результаты одинаковы, а производительность схожа, беспокоиться не о чем.

В некоторых случаях, как я уже говорил ранее, MySQL просто не сделает правильное предположение, и тогда вы сможете использовать такие инструменты, как подсказки индекса и естественные объединения. В вашем случае, я думаю, что MySQL ведет себя очень хорошо.

Чтобы узнать больше о планах производительности и исполнения, посетите следующие два сайта:

0 голосов
/ 22 февраля 2012

Если я правильно понял, результаты, которые вы получаете, одинаковы, и вы хотели бы узнать разницу между предложениями «ИЛИ» и «В» относительно скорости и того, как они работают.

Если это так, то я думаю, что ваш вопрос является возможным дубликатом этого вопроса: IN или OR в предложении SQL WHERE

...