2013-08-08 2 views
1

Я читал о «COUNT (*), где предложение« невероятно медленно в PostgreSQL ». И, исходя из MySQL, я не знаю, смогу ли я жить, не используя его снова. Я также прочитал, что даже если вы добавите предложение «где», ему придется сканировать каждую строку из результата, которая будет медленной, если у вас мало результатов. Я видел, что есть сумасшедшие хаки, использующие триггеры и дополнительные таблицы, но мне не нравится, как это выглядит. Я имею в виду, что я новичок в этой СУБД, просто начал использовать базовые функции и уже должен использовать обходные пути?Как правильно считать() в PostgreSQL?

Примером того, что мне нужно сделать, является создание механизма защиты от наводнений. Что-то вроде if "count(id) where ip = 1.2.3.4" > 100, fail instead of insert.

Так что мои вопросы:

  • Является ли это еще нерешенная проблема?
  • Будет ли иметь значение, если вместо этого я использую COUNT (id) или добавлю какое-то предложение вроде DISTINCT?
  • Как пользователи PostgreSQL выживают без учета?

ответ

3

Я думаю, что «невероятно медленно» - это огромное преувеличение :) В вашем примере у вас есть максимум 100 строк в результате, их счет будет очень быстрым. Я уверен, что вам не нужны никакие хаки или обходные пути в этом случае.

Как я понимаю, «COUNT(*) без WHERE пункта медленнее в Postgres» относится к тому, что таблицы MyISAM в MySQL хранить общее количество строк в заголовке таблицы, таким образом SELECT COUNT(*) FROM my_table является O (1) операция - просто читать значение из заголовка и все. В Postgres из-за MVCC и транзакций это невозможно, и он должен проверять каждую строку, чтобы определить, видна ли она в текущей транзакции.

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

+0

О, я вижу, отлично! Если MySQL не имеет преимущества при использовании «где», я думаю, я буду просто прекрасным =) – ChocoDeveloper

1

В этом случае вы можете limit счетчик:

select count(id) > 100 
where id = 1.2.3.4 
limit 101 

Это остановит подсчета голосов на 101, независимо от количества строк, соответствующих критериям, скажем, 100000. Если count(id) > 100, он вернет true else false.

Вы можете комбинировать этот тест с помощью команды вставки, так что вам не нужно туда и обратно на сервер:

with c as (
    select count(id) > 100 as c 
    from t 
    where id = 1.2.3.4 
    limit 101 
) 
insert into t (x, y) 
select 1, 2 
where (select c from c) 
+0

Nice catch! Благодарю. – ChocoDeveloper

2

В основном это отсортированный в PostgreSQL 9.2 с индексом только сканов. Вы должны быть в порядке, просто убедитесь, что ваш автовакуум настроен на работу часто.

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

COUNT(id) лучший стиль, поэтому вы, как правило, предпочитаете использовать его в любом случае. Я не вникнул в последствия производительности в деталях; I думаю Pg будет использовать первичный ключ в любом случае, но вам нужно будет больше копать, чем у меня есть время для проверки.

Ваше предлагаемое использование подвержено условиям гонки, которые сделают его недействительным в любой базе данных. Это не имеет значения, если вы не возражаете вставить (скажем) 120 записей вместо запланированных 100, но если вам это нужно, вы должны сначала заблокировать таблицу, иначе многие параллельные вставки все проверят, чтобы убедиться, что счет в порядке, все видят, что это так, тогда все вставляют строку.

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

Если вы используете MyISAM, вы получаете скорость в обмен на большее количество проблем, чем я мог бы надеть палку; Я предпочитаю более медленный подсчет неспособности к откату, перемещение данных, чтобы избежать ошибок в качестве обходного пути для неспособности к откату, отсутствия безопасности при столкновении и т. Д.

+0

Ouch, не думаю это гонки состояние. Благодаря! – ChocoDeveloper

Смежные вопросы