LINUX.ORG.RU

Проблемы с SELECT или кэшом

 , , ,


0

2

Добрый день. Есть компьютер (типо встроенная система) который выводит данные из нескольких таблиц на OLED дисплей по RS-232. Иногда компьютер перестает обновлять определенные значения считываемые из таблиц на дисплей. Но начинает снова обновлять их если подключить к нему смартфон в режиме модема или ноутбук (На компьютере есть веб-морда работающая с этой же базой и таблицами). Данные в базу постоянно пишутся другой программой, при выгрузке аномалий и столбняка значение нет, есть только на дисплей. За работу с дисплеем отвечает моя программа. Она опрашивает 4 таблицы и вывод данные, а так же текущее системное время. Данные в таблицах обновляются не чаще 1 раза в секунду. База требуется только для хранения и асинхронного доступа к данным.

Текущее значение из таблиц считываю так, аналогично запрашиваю данные и из других таблиц:

void read_base_sensor(char *name_table_sensor0){
        char buf1[255],buf2[255];
        conn = PQconnectdb(name_base);
        IF(PQstatus(conn)!=CONNECTION_OK){
            PQfinish(conn);
            exit(0);
        }
        else{
            sprintf(buf1,"SELECT id,time,press,temp FROM %s WHERE id=(SELECT max(id) FROM %s);", name_table_sensor0 ,name_table_sensor0);
            res = PQexec(conn, buf1);
            // выводим название столбцов
            nFields = PQnfields(res);
 
            int max_lines = PQntuples(res);
            IF(max_lines > 0){
 
            p = atof(PQgetvalue(res,max_lines-1,2));
            t = atof(PQgetvalue(res,max_lines-1,3));
 
            PQclear(res);
 
            IF(t < 0){t1 = 1; t2 = 4;}
            IF((t >= 0) && (t < 10)){t1 = 1; t2 = 5;}
            IF((t > 9) && (t < 100)){t1 = 2; t2 = 4;}
            IF(t > 99){t1 = 3; t2 = 3;}
            IF(p < 0){p1 = 1; p2 = 4;}
            IF((p >= 0) && (p < 10)){p1 = 1; p2 = 5;}
            IF((p > 9) && (p < 100)){p1 = 2; p2 = 4;}
            IF(p > 99){p1 = 3; p2 = 2;}
 
            sprintf(a_disp,"A:%*.*f\xDF\x43 %*.*fMPa;",t1,t2,t,p1,p2,p);
            }
        }
        PQfinish(conn);
    }
Этот код взят чуть не из примера по работе с БД. Есть подозрения что с залипаниями может быть как то связанно кэширование. Больше пока идей нет.

1) кэширование чего? если БД, то точно мимо

2) Прочитайте БД с ПК, и посмотрите, что там

next_time ★★★★★
()

Сделай файл журнала, пиши в него. Не забывай закрывать журнал после каждой записи. Проставив достаточно записей, узнаешь, что именно зависает. Метод поиска льва в пустыне.

den73 ★★★★★
()

SELECT id,time,press,temp FROM %s WHERE id=(SELECT max(id) FROM %s);

select id, time, press, temp from %s order by id desc limit 1;

drsm ★★
()
Ответ на: комментарий от next_time

Веб-морда работает и не знает бед. База с ПК тоже нормально работает и читается. Проблемы начинаются когда ПК от локальной сети или инета отключают.

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

Вангую один селект вместо двух быстрее будет.

Demacr ★★
()
Ответ на: комментарий от Timur1992

Проблемы начинаются когда ПК от локальной сети или инета отключают.

ну БД же вы не на свой ПК поставили? очевидно, что без инета или локальной сети он до данных не достучится и актуальные данные всё равно не получит

max_lines будет == 0 и код внутри

 IF(max_lines > 0){

не выполнится

или он как-то по-другому у вас к БД коннектится? ну вот это «как-то по-другому», видимо, не работает или падает, зато коннект проходит через модем

next_time ★★★★★
()
Ответ на: комментарий от Timur1992

Чем такой вариант лучше? Можете просветить?

С точки зрения 92 года - ничем. Ну раз в 10 быстрее, ну фигня вобщем-то.

Anoxemian ★★★★★
()
Ответ на: комментарий от next_time

БД данных стоит на этом же ПК. В неё пишут несколько других программ. Код выполняется, потому что возвращается несколько строк(названия столбцов и значения).

Timur1992
() автор топика
Ответ на: комментарий от Anoxemian

Я учту это в новой версий. А сейчас больше интересно, почему система начала стабильно работать когда я добавил bash скрипт со 100 балластовым запросами на последние значение в таблице.

Timur1992
() автор топика
Ответ на: комментарий от Anoxemian

Самое странное что это баг не удается повторить у нас(на копий образа ОС), появился только у заказчика ><

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

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

расшифруй плиз. не то чтобы это как-то повлияет на результативность, просто интересно, что здесь написано?

Anoxemian ★★★★★
()
Ответ на: комментарий от Anoxemian

Странно что не 92 году, это не понятно. Каждую секунду, другая программа опрашивает датчики по modbus rtu и записывает значения в соответствующую таблицу(INSERT INTO).

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

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

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

потрясно. я все еще не понимаю что здесь написано. какой язык у тебя родной?

а по теме - чего ты до базы докопался, ищи проблему в той хне, что информацию на дисплей выводит.

Anoxemian ★★★★★
()
Ответ на: комментарий от Anoxemian

А почему все стало стабильно работать при добавление 100 балластовых запрос? Без изменения программы работающей с дисплеем.

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

Крайняя попытка: скопипасти произвольный кусок кода из ядра этих наших линуксов и спроси, почему пятая кнопка мыши генерит не тот эвент.

Anoxemian ★★★★★
()
Ответ на: комментарий от Timur1992

ну это значит, что паритета мы добились

Anoxemian ★★★★★
()

Если честно...

То на свой вкус и цвет я бы выборку оформлял как курсор. Почему так написано тут — https://postgrespro.ru/docs/postgrespro/10/plpgsql-cursors В самом начале.

У Вас же (скорее всего, утверждать наверняка не берусь), проблема по всей видимости в том, что подвисают запросы при отключении ПК от сети. Т.е., запросы выполнены, а куда результаты девать БД даже не подозревает. И весь результат селекта висит в памяти, пока постгрес не решится его пришибить. С курсором несколько проще должно быть — в таком случае БД их просто пришибёт со всеми результатами выборки, да и дело с концом. Правда, пришибать там почти нечего будет. Ну и памяти под курсор должно сжираться меньше, т.к. по сути, это план запроса, а выборка в клиентскую часть из него идёт на уровне прикладной приблуды. Т.е., выбираем селектом не все данные и сразу, а фетчим их кусками, перемещая курсор. Постгрес и будет выбирать столько, сколько клиент сможет забрать за один раз.

Надеюсь, понятно объяснил?

/* Долбаный ведроид! */

Moisha_Liberman ★★
()
Последнее исправление: Moisha_Liberman (всего исправлений: 3)

WHERE id=(SELECT max(id) FROM %s);"

time

А как ты гарантируешь, что для более нового time — больший ID?

Ну и как вариант — транзакция с новыми данными тормозит по любой причине и в базе этих данных тупо нет на момент запроса.

x3al ★★★★★
()
Ответ на: Если честно... от Moisha_Liberman

В исходном примере для postgresql был пример как раз с курсор. Но мне он показался громоздким и я переписал просто под select. И все работало. Надо углубиться в этот вопрос.

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

да особой разницы нет, в данном случае:

  1. index only scan + index scan
  2. index scan

сравни планы сам explain analyze запрос.

drsm ★★
()
Ответ на: комментарий от Timur1992

Проблемы начинаются когда ПК от локальной сети или инета отключают.

ты случайно не по DNS имени соединяешся или ломишся на ип интерфейса, хотя надо на loopback?

drsm ★★
()
Ответ на: комментарий от drsm

Хм, из Си++ с использованием библиотеки libpq-fe.h. С веб-морды использую php подключаюсь на роль с ограниченными правами, вот так:

$dbconn = pg_connect("host=localhost port=5432 dbname=kvsm user=web1 password=12345");
  if (!$dbconn) { pg_close($dbconn); exit; }
  for($i = 1; $i <= $k; $i++){
    if($sk == 0){
      $j=$i;
      $result[$i] = pg_query($dbconn, "SELECT id,time,press,temp,w1,w2,w3 FROM $s[$j] WHERE id=(SELECT max(id) FROM $s[$j]);");
      }
    else{
      $j=$sk;
      $result[$i] = pg_query($dbconn, "SELECT id,time,press,temp,w1,w2,w3 FROM $s[$j] WHERE id=(SELECT max(id)-$i+1 FROM $s[$j]);");}
  	if (!$result[$i]) { continue; }
  }
Сейчас как оперативное решение проблемы, сделал bash скрипт который 5 раз запускает этот php и перенаправляет вывод в /dev/null 2>&1. И система стала работать стабильно.

Timur1992
() автор топика

Я бы все это выкинул и переделал на брокер сообщений/mq, где producer - прога, генерирующая данные, consumers - твоя программа и сервис, пишущий в базу. Проблему из ОП решило бы превентивно.

Но, как грится, хозяин - барин

anonymous
()
Ответ на: комментарий от anonymous

Спасибо больше за наводку! Мы обязательно рассмотрим такой вариант! Правда я не уверен что другие согласятся на столь кардинальные перемены!

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

Зря переписали.

Я тоже с сишечкой и постгресом. Курсоры работают нормально. Без «сюрпризов» по крайней мере.

Moisha_Liberman ★★
()
Ответ на: комментарий от Timur1992

Отчасти анонимусом прав.

MQTT (тот же mosquitto) для таких дел то, что доктор прописал. Но результаты один хрен придётся в базе хранить. Так что, тут эту часть особо не перепишешь.

Moisha_Liberman ★★
()
Ответ на: комментарий от drsm

Вопрос не в результатах селекта.

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

Moisha_Liberman ★★
()
Ответ на: Вопрос не в результатах селекта. от Moisha_Liberman

Возвращается всего 2 строки .__.

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

        /// продолжительность работы системы с момента последнего включения
        if(uptime < 65534){
            f0 = popen("cat /proc/uptime","r");
            if(f0 == NULL){
                printf("Error request load cpu\n");
            }
            else{
                fgets(buf1,512,f0);
                uptime = round((atof(buf1))*0.016666);
            }
            fclose(f0);
        }
        else uptime = 65535;
        /// объем свободного места
        f0 = popen("df -k | grep /dev/sd\*2 | awk '{a = $4} {print a}'","r");
        if(f0 == NULL){
            printf("Error request load cpu\n");
        }
        else{
            fgets(buf1,512,f0);
            free_memory_2mb = (atof(buf1))/1048576;
            //printf("Free%s %f\n",buf1,free_memory_2mb);
        }
        fclose(f0);

Timur1992
() автор топика
Ответ на: комментарий от Timur1992

Пишущая программа может вставить строки в обратном порядке. И технически всё зависит от порядка транзакций.

Автоувеличение SERIAL не гарантируется никем. Гарантирован только разный SERIAL для разных строк.

x3al ★★★★★
()
Ответ на: комментарий от Timur1992

Не...

Здесь вопрос не в объёме возвращаемых по селекту данных. Здесь вопрос в том, как курсор и селект обрабатывается базой. Sql-запрос имеет шанс зависнуть, курсор нет. Шибко глубоко в этот вопрос не лазил (почему так), просто использую курсоры, да не парюсь особо.

Возможно (как вариант), Вам имеет смысл закрывать базу принудительно периодически, тогда постгрес будет сбрасывать подвисшие запросы. Но это не метод. Ненадёжно, да и просто косяк. Я бы так точно не делал. С курсорами всё как-то надёжнее.

И вот, кстати, абсолютно согласен с уважаемым x3al. Я бы на такую базу даже autocommit не ставил. Потому что от «датчиков» может прилетать дохрена значений и коммитить каждое невыгодно. Лучше закинуть их в базу и потом одним коммитом зафиксировать там. Но тут Вам уже смотреть что лучше/хуже.

Moisha_Liberman ★★
()
Последнее исправление: Moisha_Liberman (всего исправлений: 1)
Ответ на: комментарий от x3al

Автоувеличение SERIAL не гарантируется никем. Гарантирован только разный SERIAL для разных строк.

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

не гарантируется что будут последовательные значения.

drsm ★★
()
Ответ на: комментарий от drsm

Нет гарантии, что «раньше начал коммит == раньше дернул nextval» и да, я встречал гонки с этим. Дебажить их в продакшне, особенно со всякими pgbouncer — то ещё удовольствие.

x3al ★★★★★
()

Все гарантии, которые ты получаешь с READ COMMITED (а это дефолт в постгресе) — то, что ты не увидишь данные до коммита. Все остальные фичи параллельных транзакций, включая phantom read — возможны. Это не совсем кэширование.

Энивей, я бы в первую очередь дебажил ту сторону, которая пишет данные.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Хоспади. Сколько же проблем и тонкостей с базой и SELECT. А по идей должна облегчить жизнь разработчикам и взаимодействие программ!

Вообщем пока проблему пофиксил 100 дополнительными SELECT, но это такой себе костыль .___.

Timur1992
() автор топика
Ответ на: комментарий от x3al

ты имеешь ввиду гонки на «раньше дернул бегин == раньше дернул некствал»? те ситуации когда два инсерта типа

insert into tbl(id, tstamp) values(default, now())

зайдут с различным порядком id и tstamp и запись с max(id) != записи с max(tstamp)

drsm ★★
()
27 июня 2019 г.

Тема закрыта, я сам себе в ногу выстрелил.

Спасибо всем большое за ответы и предложения! Особенно про оптимизацию запрос до одного SELECT и брокер сообщений!

P.S. Проблема оказалось в моем ПО, а точнее в переполнений массива и не дотестирований. Вообще когда я писал программу, то не рассчитывал что кто-то будет слишком часто передергивать USB-флешки и USB-модемы, поэтому очистка массива для запросов проводилась раз в секунду. Но как оказалось при подключений Honor 8/9, в не зависимости от выбранного режима работы (флешка/USB-модем/зарядка) телефон сначала подключится как флешка HiSuite размером 4 Мб, а потом только переходит в режим выбраны вами. И это все в пределах одной секунды, жизнь меня к такому не готовила.

Теперь загадка, отгадайте какие телефоны у моих коллег которые ездили сдавать систему ХD

Timur1992
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.