2回目のCUBRIDコンテスト。 ソリューションを検索する

オープンソースプロジェクトのCUBRIDがコンテストを開催することを決定したことを多くの人が聞いたと思います。作業を提出する時間はすでに終わっているので、コンテストタスクの解決方法、使用した方法、DBMS CUBRIDの機能について説明します。



割り当て(概算)



厳密に定義されたタイプの列を含むテーブルで構成されるデータベースが提供されます。
VARCHAR, CHAR, STRING, INT, SMALLINT, BIGINT, NUMERIC, FLOAT, DOUBLE, DATE, TIME, DATETIME  TIMESTAMP.
      
      





データベースで最も頻繁に検出される数値以外の値(数字だけで構成されていない値)と使用回数を見つける必要があります。 回答は結果テーブルに書き込まれる必要があります。 それだけです(要するに、コンテストページで詳細を読んでください)。



タスク分析



ソリューションは、より高速でRAMに対する要求が少ない場合にのみ、他の製品よりも際立っています(多くの+値が存在する可能性があります)。 したがって、一時テーブルを使用して、統計のすべてのメンテナンスをsubdに任せました。 そして、すべての挿入要求に対してon dublicate key update key update "count"="count"+1



のプレフィックスon dublicate key update key update "count"="count"+1



使用してカウンターを更新することにしました。 テストでは役に立たないことが示されたため、ハッシュを使用しませんでした(ほとんどの場合、文字列キーのハッシュはCUBRIDで既に使用されています)。 マルチスレッド化も効果がありません。ある時点では、1つのプロセスのみがテーブル内のデータを変更でき、他のプロセスは待機する必要があります(ロックを解除できますが、データの整合性は侵害されます)。



解決策



次の解決策が思い浮かびます。

 init(); foreach(list_tables() as $table){ process_table($table); } save_result();
      
      





次の4つの機能のみを実装します。

  1. init



    は、一時テーブルを作成する関数です。

    サンプルコード:

     global $tempTableName,$conn; $tempTableName='"temp'.rand(0,32767).'"'; $q='CREATE TABLE '.$tempTableName.'( "val" character varying(255) NOT NULL, "count" bigint DEFAULT 1 NOT NULL, CONSTRAINT pk_temp_hash_val PRIMARY KEY("val") )'; cubrid_execute($conn,$q);
          
          



  2. list_tables



    現在のデータベース内のテーブルのリストを取得する関数。

    CUBRIDはMySqlに似ているため、最初に見ることができるのはSHOW TABLES



    、バージョン8.3.1ではサポートされていません(また、データベース内のテーブルのリストを取得することについてドキュメントがあまりない)ので、すべてCubrid WebQueryプロジェクトページに移動しますコードを調べます。 せっかちな人のために、必要なSQLクエリをすぐに引用します。

      select class_name as table_name from db_class where class_type='CLASS' and is_system_class='NO' and class_name!='results' order by a asc;
          
          





    それをコードで使用します。



    cubrid_schema



    関数を使用できますが、それでもクラスタイプをフィルタリングして追加する必要があります。 処理します。
  3. process_tables



    はソリューション全体で最も興味深い関数であり、それに応じて統計を作成します。



    多くの可能な実装オプションがあります。

    • select * + setFetchSize/cubrid_unbuffered_query





      私のテストが示したように(興味のある人なら誰でも-Javaソリューションは投稿の下部にあるアーカイブにも含まれています)、最速のソリューションではありません。
    • javaタイプのストアド関数の呼び出しでselect *



      +条件をselect *





      where "int"<0 and counter("int") or length(translate("str",'0123456789',''))>0 and counter("str")





      counter



      は値をdbに保存し、falseを返します。

      ただし、このようなリクエストにより、システムがフリーズしました(CUBRIDでは明らかにjavaの関数が完全に磨かれていません)。
    • insert from select ... on dublicate key update "count"="count"+1





      私がメインのオプションとして位置付けているのはこのオプションです(ただし、phpドライバーのエラーを考慮して、二重値を処理するときは松葉杖を考え出す必要がありました)。


    列のタイプごとに独自の処理が行われることが明らかなので、列とそのタイプのリストを取得する必要があります。

    • integer



      型(またはdecimal



      ない10進数)の場合、符号チェックで十分です。

    • すべての文字列値について、すべての数字を削除してから、文字列の長さを確認します。

    • 他のすべての値については、チェックは不要です。


    質問も発生します-値を文字列に変換する形式。 フォーラムで長い議論を重ねた結果、最も理想的なオプションはcubridマネージャーと同じ形式を使用することであるという結論に達しました(選択要求の結果を表示する場合)。



    同じ種類の検証を異なる種類の列(+同じデータ型の異なる名前)に適用できるため、すべての条件と「エイリアス」を個別の配列に入れます。

     $aliases=array( "STRING"=>"VARCHAR", 'CHAR'=>'VARCHAR', "INT"=>'INTEGER', "SHORT"=>'INTEGER', 'SMALLINT'=>'INTEGER', 'BIGINT'=>'INTEGER', 'DECIMAL'=>'NUMERIC', 'DEC'=>'NUMERIC', "REAL"=>'FLOAT', "DOUBLE PRECISION"=>'DOUBLE', ); // column process criteria and/or format $handlers=array( 'VARCHAR'=>array( 'select'=>'cast(%s as varchar(255))', 'criteria'=>"length(translate(%s,'0123456789',''))>0", ), 'INTEGER'=>array( 'select'=>'cast(%s as varchar(255))', 'criteria'=>"%s<0" ), 'FLOAT'=>array( 'select'=>"to_char(%s,'9.999999EEee')", ), 'DOUBLE'=>array( 'select'=>"to_char([double],'9.9999999999999999EEee')", ), 'DATE'=>array( 'select'=>"TO_CHAR(%s,'YYYY-MM-DD')", ), 'TIME'=>array( 'select'=>"TO_CHAR(%s,'HH24:MI:SS')", ), 'DATETIME'=>array( 'select'=>"to_char(%s,'YYYY-MM-DD HH24:MI:SS.FF')", ), 'TIMESTAMP'=>array( 'select'=>"to_char(%s,'YYYY-MM-DD HH24:MI:SS')", ), 'DEFAULT'=>array( 'select'=>'cast(%s as varchar(255))', ) );
          
          





    そして最後に、最終サイクル:

     foreach(get_columns($q) as $column){ //echo "\tProcess column:".$column['column']."\n"; while(isset(self::$aliases[$column['type']])) $column['type']=self::$aliases[$column['type']]; // If column is decimal and has no precision then convert type to integer if($column['type']==='NUMERIC' && $column['scale']===0) $column['type']='INTEGER'; $criteria=(isset(self::$handlers[$column['type']])) ? self::$handlers[$column['type']]: self::$handlers["DEFAULT"]; $toSelect=(isset($criteria['select'])) ? $criteria['select'] : '%s'; // Depending of the column type build appropiate criteria $q='insert into '.$tempTableName.' ("hash","val") '. 'SELECT 1,'.$toSelect.' '. 'FROM `'.$qtable.'` '. 'where %s is not null and '.$criteria.' '. 'ON DUPLICATE KEY UPDATE "count"="count"+1'; $q=str_replace('%s','`'.$this->escape($column['column']).'`',$q); cubrid_execute($q); }
          
          





  4. save_result



    結果を保存し、一時テーブルを削除します

    記事を過負荷にしないために、結果を保存するためにSQLクエリのみを引用します

     'replace into results ("userid","most_duplicated_value","total_occurrences") select \''.cubrid_real_escape_string($userid).'\',val,"count" from "'.$tempTableName.'" order by "count" desc limit 1'
          
          





    テスト中にコードが何度も実行され、挿入の場合、同じテストデータのセットに対してエラーが発生するため、 replace



    使用されます。


結論



完全に完成していないソリューションを送信しましたが(charに問題があり、一時テーブルの名前がランダムではなく、null値のチェックもありませんでした)、最後の瞬間に、キュービッドのパフォーマンスを把握し、javaをマスターしました最初のレベルでは、英語で練習し、多くの貴重な経験を得ました。 実験的な方法を使用して、CUBRIDには非常に高速なクエリインタープリターがあり、テーブルで非常に高速に動作することがわかりましたが、RAMの一時テーブルと適切なドキュメントのサポートが不足しています(これは簡単なヘルプのようです)。 CUBRIDは非常に生産的なDBMSであることが判明したため、将来(見つかったエラーの一部が修正されたとき)、高負荷のプロジェクトで使用します。



参照資料



  1. Curid it-コンテストページ。
  2. Cubrid itフォーラム -トークページ。
  3. Cubrid Webquery -cubridマネージャーの類似物で、便利なSQLクエリが含まれています。
  4. Cubridソリューション -私のソリューション、修正済み(テストデータベースに入力するjava + php +コード)。




PS:これはハブに関する私の最初の記事です。すべてのルールを考慮に入れようとしました(ただし、何かが間違っている場合-書き、正しいこと、間違いから学びます)。 私はトピックをsqlブログに転送することにしました(cubridの会社のブログでは機能しません)。

PS2:cubridのHabrauserは適切なブログをアドバイスしました。 そこに移動しました。

PS3:コンテストの勝者の決定もハブで公開されます



All Articles