Строка синтаксического анализа в argv/argc

ПРИМЕЧАНИЕ , что это - общий взгляд на хранимые процедуры, не отрегулированные к определенному DBMS. Некоторый DBMS (и ровные, различные версии того же DBMS!) может работать вопреки этому, таким образом, Вы захотите перепроверить со своим целевым DBMS прежде, чем предположить, что все это все еще содержит.

я был ASE Sybase, MySQL и DBA SQL Server на - и прочь с тех пор в течение почти десятилетия (наряду с разработкой приложений в C, PHP, МН / SQL, C#.NET и Ruby). Так, у меня нет конкретного топора для шлифования в этом (иногда) священной войны.

исторический выигрыш в производительности сохраненного procs обычно были от следующего (без определенного порядка):

  • Предварительно проанализированный SQL
  • Предварительно сгенерированный план
  • выполнения запросов Уменьшенная сетевая задержка
  • Потенциальные преимущества кэша

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

Все еще преимущество? Не очень примечательный вообще на современном ЦП, но если Вы отправляете единственный SQL-оператор, который является ОЧЕНЬ большим eleventy-миллиардом времен секунда, парсинг наверху может сложить.

Предварительно сгенерированный план выполнения запросов. Если у Вас есть много СОЕДИНЕНИЙ, перестановки могут стать довольно неуправляемыми (современные оптимизаторы имеют пределы и сокращения по причинам производительности). Это не неизвестно для очень сложного SQL для имения отличный, измеримый (я видел, что сложный запрос берет 10 + секунды только для генерации плана, прежде чем мы настроили DBMS), задержки из-за оптимизатора, пытающегося выяснять "около лучшего" плана выполнения. Хранимые процедуры будут, обычно, хранить это в памяти, таким образом, можно будет избежать этих издержек.

Все еще преимущество? Большая часть DBMS (последние выпуски) будет кэшировать планы запросов для ОТДЕЛЬНЫХ SQL-операторов, значительно уменьшая дифференциал производительности между сохраненным procs и специальным SQL. Существуют некоторые протесты и случаи, в которых это не имеет место, таким образом, необходимо будет протестировать на целевом DBMS.

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

ПРЕДУПРЕЖДЕНИЕ Кэшируемые планы запросов не являются панацеей производительности. Иногда план запросов, который сгенерирован, является субоптимальным. Например, если Вы отправляете SELECT * FROM table WHERE id BETWEEN 1 AND 99999999, DBMS может выбрать полное сканирование таблицы вместо индексного сканирования, потому что Вы захватываете каждую строку в таблице (так sayeth статистика). Если это - кэшированная версия, то можно получить низкую производительность, когда Вы позже отправляете SELECT * FROM table WHERE id BETWEEN 1 AND 2. Обоснование позади этого выходит за рамки этой регистрации, но для дополнительных материалов для чтения см.: http://www.microsoft.com/technet/prodtechnol/sql/2005/frcqupln.mspx и http://msdn.microsoft.com/en-us/library/ms181055.aspx и http://www.simple-talk.com/sql/performance/execution-plan-basics/

, "Таким образом, они решили, что предоставление чего-либо кроме общих ценностей, когда компиляция или перекомпилировали, было выполнено, привел к компиляции оптимизатора и кэшированию плана запросов для того конкретного значения. Все же, когда тот план запросов был снова использован для последующего выполнения того же запроса для общих ценностей (вЂ˜M’, вЂ˜R’, или вЂ˜T’), это привело к субоптимальной производительности. Эта субоптимальная проблема производительности существовала, пока запрос не был перекомпилирован. В той точке, на основе @P1 предоставленного значения параметра, запрос мог бы или не мог бы иметь проблемы производительности".

Уменьшенная сетевая задержка А при выполнении того же SQL много раз - и SQL составляет в целом многих КБ кода - замена, которая с простым "должностным лицом foobar" может действительно сложить. B) Сохраненный procs может использоваться для перемещения процессуального кодекса в DBMS. Это сохраняет стягивание больших объемов данных клиенту только для имения его, передают струйку обратно информации (или ни один вообще!). Аналогичный выполнению СОЕДИНЕНИЯ в DBMS по сравнению с в Вашем коде (общий любимый WTF!)

Все еще преимущество? А современный 1 ГБ (и 10 ГБ и!) Ethernet действительно делают это незначительным. B) Зависит от того, насколько влажный Ваша сеть - почему толчок несколько мегабайтов данных назад и вперед ни на каком серьезном основании?

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

Все еще преимущество? , Если Ваше приложение не имеет доступ общей памяти к данным DBMS, край всегда будет к сохраненному procs.

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

Параметризованный / Подготовленный SQL
Своего рода пересечение хранимых процедур и специального SQL, они - встроенные SQL-операторы на базовом языке, который использует "параметры" для значений запроса, например:

SELECT .. FROM yourtable WHERE foo = ? AND bar = ?

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

Специальный SQL Просто открывают консоль для Вашего DBMS и типа в SQL-операторе. В прошлом они были "худшими" исполнителями (в среднем), так как DBMS не имел никакого способа предварительно оптимизировать запросы как в том, чтобы параметризовать/хранившем proc метод.

Все еще недостаток? Не обязательно. Большая часть DBMS имеет способность к "абстрактному" специальному SQL в параметризованные версии - таким образом более или менее отрицание различия между двумя. Некоторые делают это неявно или должны быть включены с установкой команды (SQL-сервер: http://msdn.microsoft.com/en-us/library/ms175037.aspx , Oracle: http://www.praetoriate.com/oracle_tips_cursor_sharing.htm ).

извлеченные Уроки? Закон Гордона Мура продолжает идти на и оптимизаторы DBMS, с каждым выпуском, становиться более сложным. Несомненно, можно поместить каждый глупый SQL-оператор подростка в сохраненном proc, но просто знать, что программисты, работающие над оптимизаторами, очень умны и постоянно ищут способы улучшить производительность. В конечном счете (если это уже не здесь) специальная производительность sql станет неразличимой (в среднем!) от производительности хранимой процедуры, таким образом, любой вид [1 116] крупный использование хранимой процедуры ** только по "причинам производительности" ** уверенный походит на преждевременную оптимизацию мне.

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

30
задан Tunaki 5 February 2017 в 14:57
поделиться

5 ответов

If glib solution is overkill for your case you may consider coding one yourself.

Then you can:

  • scan the string and count how many arguments there are (and you get your argc)
  • allocate an array of char * (for your argv)
  • rescan the string, assign the pointers in the allocated array and replace spaces with '\0' (if you can't modify the string containing the arguments, you should duplicate it).
  • don't forget to free what you have allocated!

The diagram below should clarify (hopefully):

             aa bbb ccc "dd d" ee         <- original string

             aa0bbb0ccc00dd d00ee0        <- transformed string
             |  |   |    |     |
   argv[0] __/  /   /    /     /
   argv[1] ____/   /    /     /
   argv[2] _______/    /     /
   argv[3] ___________/     /
   argv[4] ________________/ 

A possible API could be:

    char **parseargs(char *arguments, int *argc);
    void   freeparsedargs(char **argv);

You will need additional considerations to implement freeparsedargs() safely.

If your string is very long and you don't want to scan twice you may consider alteranatives like allocating more elements for the argv arrays (and reallocating if needed).

EDIT: Proposed solution (desn't handle quoted argument).

    #include <stdio.h>

    static int setargs(char *args, char **argv)
    {
       int count = 0;

       while (isspace(*args)) ++args;
       while (*args) {
         if (argv) argv[count] = args;
         while (*args && !isspace(*args)) ++args;
         if (argv && *args) *args++ = '\0';
         while (isspace(*args)) ++args;
         count++;
       }
       return count;
    }

    char **parsedargs(char *args, int *argc)
    {
       char **argv = NULL;
       int    argn = 0;

       if (args && *args
        && (args = strdup(args))
        && (argn = setargs(args,NULL))
        && (argv = malloc((argn+1) * sizeof(char *)))) {
          *argv++ = args;
          argn = setargs(args,argv);
       }

       if (args && !argv) free(args);

       *argc = argn;
       return argv;
    }

    void freeparsedargs(char **argv)
    {
      if (argv) {
        free(argv[-1]);
        free(argv-1);
      } 
    }

    int main(int argc, char *argv[])
    {
      int i;
      char **av;
      int ac;
      char *as = NULL;

      if (argc > 1) as = argv[1];

      av = parsedargs(as,&ac);
      printf("== %d\n",ac);
      for (i = 0; i < ac; i++)
        printf("[%s]\n",av[i]);

      freeparsedargs(av);
      exit(0);
    }
12
ответ дан 27 November 2019 в 23:17
поделиться

Всегда замечательный glib имеет g_shell_parse_args () , что похоже на то, что вам нужно.

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

Если вы не очень скупы на память, сделать это за один проход без перераспределения должно быть легко; просто предположите наихудший случай, когда каждый второй символ является пробелом, таким образом предполагая, что строка из n символов содержит не более (n + 1) / 2 аргументов и (конечно) не более n байтов текста аргумента (исключая терминаторы).

9
ответ дан 27 November 2019 в 23:17
поделиться

В конце концов я написал функцию для этого сам, я не думаю, что она очень хороша, но она работает для моих целей - не стесняйтесь предлагать улучшения для всех, кому это понадобится в будущем :

void parseCommandLine(char* cmdLineTxt, char*** argv, int* argc){
    int count = 1;

    char *cmdLineCopy = strdupa(cmdLineTxt);
    char* match = strtok(cmdLineCopy, " ");
 // First, count the number of arguments
    while(match != NULL){
        count++;
        match = strtok(NULL, " ");
    }

    *argv = malloc(sizeof(char*) * (count+1));
    (*argv)[count] = 0;
    **argv = strdup("test"); // The program name would normally go in here

    if (count > 1){
        int i=1;
        cmdLineCopy = strdupa(cmdLineTxt);
        match = strtok(cmdLineCopy, " ");
        do{
            (*argv)[i++] = strdup(match);
            match = strtok(NULL, " ");
        } while(match != NULL);
     }

    *argc = count;
}
2
ответ дан 27 November 2019 в 23:17
поделиться

К сожалению C ++, но для других, которые могут искать такую ​​библиотеку, я рекомендую:

ParamContainer - простой в использовании синтаксический анализатор параметров командной строки

Действительно маленький и очень простой.

p.addParam("long-name", 'n', ParamContainer::regular, 
           "parameter description", "default_value");  

programname --long-name = value

cout << p["long-name"];
>> value

По моему опыту:

  • очень полезно и просто
  • стабильно на производстве
  • хорошо протестировано (мной)
0
ответ дан 27 November 2019 в 23:17
поделиться

В LIBTINYC Мэтта Пейтрека есть модуль argcargv.cpp, который принимает строку и преобразует ее в массив аргументов с учетом аргументов в кавычках. Обратите внимание, что он специфичен для Windows, но довольно прост, поэтому его будет легко перейти на любую платформу, которую вы хотите.

2
ответ дан 27 November 2019 в 23:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: