スキップしてメイン コンテンツに移動

投稿

XMLStarletを使ってLinuxのコマンドラインからXMLを操作

LinuxのコマンドラインからXMLを操作する際には、 XMLStarlet を使うと便利です。 ただし、複雑な処理を適用する場合は、素直にプログラミング言語で提供されているDOMやParserを使う方が良いと思います。 例えば、下記のコマンドを実行すると、特定のxpathにマッチした要素の数を数えることができます。 # selはxml documentへのクエリや検索を実行するためのオプション # -tはテンプレートを指定するためのオプションで、下記の例では、さらに-vで指定したxpathを実行するように命令しています。 xml sel -t -v &quote;count(/xml/table/row)&quote; data.xml オプションは色々あるので、公式ドキュメントを読んで色々試してみるのが近道かと思います。

Nexus 7 (2012) に Android 7.1.2を無理やり導入したときに発生したバッテリの消費問題

Nexus 7 (2012)にAndroid 7.1.2を適用 長年愛用しているNexus 7 (2012)は公式にはAndroid 5.1.1でサポート打ち切られていますが、 調べたところ、下記の記事から有志の作ったAndroid 7.1.2 AOSPを焼けることがわかり早速試してみました。 https://ameblo.jp/nattolecats/entry-12307126801.html Nexus 7 (2012)上でAndroid 7.1.2を通常動作させるところまで行き、満足していました。(動きは比較的軽快でした。)   ところが!  Android 7.1.2 適用前よりも、スリープ時に「Miscellaneous(=雑多)」とい う項目でバッテリがどんどん消費されてしまうという問題が発生し、原因の解明に四苦八苦することになりました orz スリープ時のバッテリ消費の原因 結論から言うと、私の適用したROM ( aosp_grouper-7.1.2-ota-eng-20170811.ds.zip  )のビルドタイプがuserdebugになっていたこと原因でした。 ro.build.type=userdebug どうもデバッグ用の何らかのプロセスが走って、電力を消費してしまうようです。 通常は、 ro.build.type=user です。というわけで、このro.build.typeを書き換えればいいのですが (例えば BuildProp Editor を利用)、build propertyは、root権限がないと書き換えられないため、今度はroot化必須、、、となったところで私は「もういいやwww」となりました。 最終的には、Googleから公式の提供されているFactory Image "nakasi" for Nexus 7 (Wi-Fi)   をGoogle先生の言われたとおり適用して、まっさらな Android 5.1.1状態で使うことにしました。動作がもっさりしていたり、最新のアプリがインストールできなかったり、セキュリティ大丈夫なのか、とかいろいろ問題ありますが、自分はNexus 7を読書用と割り切って使うことにしました。 結局Nexus 7

MySQLのSQL_CALC_FOUND_ROWS使用上の注意

MySQLのSQL_CALC_FOUND_ROWSを使用する際の無駄なメモリ消費に注意 ページング機能の実装などのために、ヒットした全件数を取得する必要のある場合があるかと思います。 その場合、下記のようにSQL_CALC_FOUND_ROWSを使うと、検索結果に加えて、そのクエリの全ヒット件数が取得できます。 SELECT SQL_CALC_FOUND_ROWS table.column1, table.column2 ...(途中省略)... FROM table WHERE (条件) しかし、SQL_CALC_FOUND_ROWSを使うと、「絞り込んだ結果にヒットする全べての行の結果のセットを作成する」という大きな欠点があります。 これは、LIMIT, OFFSETを指定していても実行されてしまうので、 SELECTで指定するカラム数やデータ量が多い SELECTの結果返ってくる行数が多い 場合、無駄に領域(≒メモリ)を消費してしまうので注意が必要です。 例えば、100万行検索対象としてヒットするクエリの場合、仮にLIMIT 20と指定して最初の20行を取得するようにクエリを書いても、その100万行分の結果セットが作成されてしまうということになります。 対応策 根本的な対応策としては、SQL_CALC_FOUND_ROWSを使わない(結果行数の取得はCOUNTを用いた別クエリで取得する、結果行数をあらかじめサマリーテーブルに保持しておく)ことですが、 SQL_CALC_FOUND_ROWSをどうしても使う必要がある場合は、 SELECT SQL_CALC_FOUND_ROWS primary_id のように最低限のカラムを指定して結果行セットを取得 (LIMIT OFFSET指定前提) 取得したprimary_idを使って必要なデータを取得 して、SQL_CALC_FOUND_ROWSで使用する領域をできるだけ減らすことで、対応するしかないと思います。 世の中ではLIMIT, OFFSETは使わない方がよいとよく書かれていますが、 SQL_CALC_FOUND_ROWSは、書いてしまえばどんなときも検索にヒットする全結果行セットを作成するので、同じくらい使用する際には注意が必要です。

MySQL: SELECTの結果をUNIONして ORDER BYする際の最適化方法

SELECTの結果をUNIONして ORDER BY する際には下記の点に注意する必要があります。 無駄なメモリ消費 ソートにINDEXが利かない (≒CPU負荷増大) 対応策 可能であればPush-down Condition (各サブクエリ内でORDER BY, LIMIT, OFFSETを適用してからUNION, ORDER BYを実行する)を利用することで、 パフォーマンスを改善できる場合があります。 下記に例を示します。 もともとのクエリ SELECT tmp.* FROM ( SELECT tableA.column1, tableA.column2 FROM tableA WHERE (条件) UNION ALL SELECT tableB.column1, tableB.column2 FROM tableB WHERE (条件) ) AS tmp ORDER BY tmp.column1, tmp.column2 LIMIT 100, 20 Push-down Conditionを用いて書き直したクエリ SELECT tmp.* FROM ( SELECT tableA.column1, tableA.column2 FROM tableA WHERE (条件) ORDER BY tableA.column1, tableA.column2 LIMIT 30 # <- 10 (offset) + 20 (limit) UNION ALL SELECT tableB.column1, tableB.column2 FROM tableB WHERE (条件) ORDER BY tableB.column1, tableB.column2 LIMIT 30 # <- 10 (offset) + 20 (limit) ) AS tmp ORDER BY tmp.column1, tmp.column2 LIMIT 10, 20 ただしこのPush-down Conditionの手法も下記の場合は、効果が半減しますので注意が必要です。 OFFSETの値が大きい場合は、結局全結果セットUNIONと変わらない サブクエリ内のソートで、INDEXが効かない場合

MySQLのクエリチューニングの基本的な考え方

今回は、筆者が気をつけている、MySQLのクエリチューニングの基本的な考え方について、紹介しようと思います。 基本的な指針としては、下記を守ることが重要です。 MySQLがクエリの実行で使用する領域(≒メモリ使用量)を減らす。 クエリ対象の行を減らす (INDEX, サマリーテーブルを駆使)。 上記の基本的な指針に基づいて、クエリを組み立てる際は以下の点を考慮するとよいと思います。 SELECTで指定する行は少なくする。 JOINするテーブルの数は減らす。 TEXTや大きいサイズのVARACHARでのORDER BYは極力避ける。SUBSTRなどを使ってカラムの一部データのみを使うことも考慮。 EXPLAINを実行した際に Extra: Using where; Using temporary; Using filesort と表示される場合は要チェック。 確認部分: 巨大なTemporaryテーブルが作成されないように注意。 対策: 「ソート部分でINDEXを使えないか」「サマリーテーブルを使って余計なJOINを減らしソート対象の行数を減らせないか」を検討。 INDEXを効かせる。 テーブル設計段階でどのカラムにINDEXを張るかをしっかり検討 (当たり前ですが。) 特にソートの必要がある場合は、できるだけINDEXやPRIMARY KEYを利用できるようにクエリやテーブルを設計。 基本MySQLのクエリオプティマイザに従うべきですが、あえて特定のINDEXを効かせる/効かせない場合は FORCE INDEX STRAIGHT_JOIN の利用も検討。ただし、クエリの実行プランはデータによっても変わるので、基本、FORCE INDEXやSTRAIGHT_JOINは使うべきではないと筆者は考えています。 想定される状況が限定的 解決しようとしているクエリの問題が明確 性能改善度合いが大きい ときのみ、FORCE INDEXやSTRAIGHT_JOINは使用すべきかと思います。また強制したクエリの実行プランが最悪の実行プランになった場合も想定することをお勧めします。 複雑なネストクエリは避ける。 確認部分: Temporaryテーブル(INDEXが効かない!)が作成される可能性が高い上、メモリも大量に

Java 8の機能利用に伴うSpring 4へのバージョンアップ

下記の順序で環境を更新していったときに、問題が起こったのでメモしておきます。 Spring 3 + Java 7: もともとの環境。 Spring 3 + Java 8 (Java 8のラムダ機能などのJava 8からの新機能は未使用): 問題なく動作。 Spring 3 + Java 8 (Java 8のラムダ機能などのJava 8からの新機能を使用): 起動時に下記のExceptionが発生 org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL ...(途中省略)... java.lang.ArrayIndexOutOfBoundsException: xxx Googleで調べたところJava 8から導入された新機能を使う場合は、Spring 4に更新しないといけないようです。 Mavenとかは、使っていなかったので、Spring Frameworkから提供されているspring-xxx系のjarすべてをバージョン3.X系からバージョン4.X系のものに手動で置き換えました。 (Spring Frameworkはバージョン5.X系ももう出ているのですね。既に置いていかれているorz...) 無事にアプリケーションが起動するようになりました! ただ普通は、こんな乱暴にjarを入れ替えることは難しいので、アップデートはもっと慎重にやるべきでしょうね。

Google App Engineで外部のURLにアクセス

Google App Engine(GAE)から外部のネットワークへ接続する際の注意 Google App Engine(GAE)の開発環境の移行の際にJava 7からJava 8へ移行しました。 その際、GAEから、java.net.URL.openConnectionを使って普通に外部ネットワークのAPIを呼び出そうとすると下記のエラーが発生するようになってしまいました。 java.net.UnknownHostException: ホスト名 いろいろ調べていくと、下記のページにたどり着きました。 https://cloud.google.com/appengine/docs/standard/java/issue-requests 上記の表を間単に日本語訳すると URLのフェッチ方法 Java 7 Java 8 UrlFetch API Calls com.google.appengine.urlfetch.*以下のクラスを使う。無料で使用できる部分あり。 com.google.appengine.urlfetch.*以下のクラスを使う。無料で使用できる部分あり。 Javaネイティブのjava.net.URL.openConnectionなどを使う方法 無料ユーザも制限なく利用可能。 無料ユーザは、利用不可。 java.net.UnknownHostException、java.net.SocketTimeoutException、java.io.IOException とかが投げられる。 まとめると、 GAEで外部ネットワークへアクセスする方法には「GAEが提供するUrlFetch API Calls」「Javaネイティブのjava.net.URL.openConnection」の2つ方法がある。 Java 7では、「GAEが提供するUrlFetch API Calls」「Javaネイティブのjava.net.URL.openConnection」は無料でどちらの方法も利用可能。 Java 8で無料で利用できるのは「GAEが提供するUrlFetch API Calls」のみ。 Java 8で「Javaネイティブのjava.net.URL.openConnectionの方法」は課金ユーザーのみ利