2012-01-06 2 views
1

Я создаю несколько запросов AJAX, которые должны собирать данные META (имена столбцов) для запроса одного ввода через несколько столбцов в базе данных ... например, если вы ищете Джон Андерсон и адрес электронной почты [email protected] «и» будет соответствовать Андерсоном и [email protected]MySQL как работает SELECT * в MySQL/Query Efficiency

запрос выглядит следующим образом:

// The joins might not make sense I took the database name out, since it is 
// the same as the company I work for... 
$querySyntax = "SELECT 
        idAccount, 
        FirstName, 
        LastName, 
        Email, 
        Phone, 
        CCCity, 
        CCState 
       FROM 
        account Right Join 
        states On account.CCState = 
        states.ID WHERE "; 

$cols = $dbo->query("SELECT * FROM account"); 

$colcount = (count($cols) > 0 ? $cols->columnCount() : count($cols)); 

for ($ii=0; $ii < count($search); $ii++) { 
    if ($ii>0) 
     $querySyntax = $querySyntax . " AND "; 
     $querySyntax = $querySyntax . "("; 

    for ($i=0; $i<$colcount; $i++) { 
     if ($i>0) 
      $querySyntax = $querySyntax . " OR "; 
      $meta = $cols->getColumnMeta($i); 
      $colNames[$i] = $meta['name']; 
      $querySyntax = $querySyntax . $colNames[$i] . " LIKE '%" . $search[$ii] . "%'"; 

     } 
     $querySyntax = $querySyntax . ")"; 

    } 

    $querySyntax .= " LIMIT 50"; 

$found = $dbo->query($querySyntax); 
for($i=0; $row=$found->fetch();$i++) { 
     $result[$i] = $row; 
} 

Ok, с этим сказал, является есть лучший способ получить имена столбцов, чем запрос «SELECT * ...»?

Когда вы запускаете SELECT *, он действительно считывает и сохраняет каждую запись в памяти? Это может быть чрезвычайно медленным, как только база данных будет заполнена тысячами записей, которые у нас есть.

+3

Если вы не используете все поля, придерживайтесь назвать их всех, как вы это сделали. – jValdron

+0

Если вы только после списка столбцов, не могли бы вы просто использовать «limit 1», чтобы получить только одну запись, нет необходимости возвращать все записи, если вам нужны только метаданные? – dougajmcdonald

+1

Не беспокойтесь о производительности, пока не сможете _prove_ это проблема. До тех пор сосредоточьтесь на других вещах, которые важнее _now_, например, чтобы получить продукт в дверь. – cdeszaq

ответ

2

Это довольно расточительно, и да, это извлекает все записи из этой таблицы. Если вас интересует только перечисление столбцов, вы можете, вероятно, использовать оператор SHOW COLUMNS FROM <your table> (docs), чтобы получить только список столбцов. Более того, вы определенно не должны делать это до каждый запрос. Лучше сделать это только один раз, а затем сохранить список столбцов для будущего использования, поскольку они вряд ли будут меняться во время сеанса пользователя, не так ли?

+0

Ах, спасибо! и очень хорошая идея для хранения результатов! – guyfromfl

4

SHOW COLUMNS (и большинство других команд SHOW, которые запрашивают метаданные) внутренне функционируют как запросы к INFORMATION_SCHEMA. When you do that против таблиц InnoDB, MySQL пытается обновить статистику таблицы, запросив случайные страницы из соответствующей таблицы. В результате команды SHOW и запросы к INFORMATION_SCHEMA ужасно медленны.

Есть несколько обходных путей:

  1. SET GLOBAL innodb_stats_on_metadata=0, который отключает автоматическую Recalc статы таблицы каждый раз, когда вы просматриваете метаданные для таблиц InnoDB.

    Недавний блог Петра Зайцева: Solving INFORMATION_SCHEMA slowness и руководство пользователя Dynamically Changing innodb_stats_on_metadata.

  2. Используйте DESC account, который намного быстрее, чем запрос INFORMATION_SCHEMA.

  3. Используйте PDOStatement::getColumnMeta(), как вы это делаете, но используйте prepare() вместо query(). Таким образом, он проанализирует ваш запрос, но не выполнит его или не попытается получить строки результатов. Проверьте это внимательно, потому что getColumnMeta() является «экспериментальным» и, вероятно, ошибкой.

Однако, вы обнаружите, что LIKE '%search%' предикаты will perform poorly anyway. Вы должны использовать реальное полнотекстовое решение поиска, такое как Sphinx Search или Apache Solr.


PS: При кодировании цикла в PHP, то лучше, чтобы вычислить количество раз до цикла, а не на каждой итерации цикла.

for ($ii=0; $ii < count($search); $ii++) { 

Должно быть

$c = count($search); 
for ($ii=0; $ii < $c; $ii++) { 
+0

Ничего себе благодаря советам! Вы действительно знаете свой MySQL. Вы уже писали мои сообщения. Спасибо за кончик петли. Я никогда не думал об этом, но это сокращает все до 1 теста функции count() ... PS, я просто заказал вашу книгу: D – guyfromfl

+0

Вы также можете использовать функцию индекса FULLTEXT для MySQL, если вы делаете вторичный таблица для поисковых целей типа MyISAM. – tadman

+1

@tadman, да, и, к счастью, полный текст для InnoDB идет в MySQL 5.6. –