萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

Solr vs MySQL 查詢性能深度對比:千萬級數據下的全文檢索與聚合分析實測

面對千萬級數據量,MySQL 即使加索引仍難以滿足複雜檢索與多維聚合需求。本文通過實測數據對比 MySQL(有/無索引)、Solr(/select vs /export)、Solr Facet 聚合在範圍查詢、ID 列表獲取、統計分析場景的性能差異,並給出架構選型建議。

測試環境與基線

  • 數據量:10,407,608 條(Num Docs)
  • 查詢場景:時間範圍 2014-12-06 00:00:00 ~ 2014-12-10 21:31:55
  • MySQL 表:tf_hotspotdata_copy_test,含 collectTime、deviceID、id 等字段

場景一:範圍查詢返回全字段(結果集 ~22 萬行)

方案耗時說明
MySQL 無索引30s全表掃描
MySQL 有索引 (collectTime)2s索引範圍掃描 + 回表
Solr /select (QTime)72ms僅索引查詢耗時
SolrJ /select 獲取結果集12s含磁盤讀取 stored 字段 + HTTP 傳輸開銷

結論:Solr 索引查詢極快,但大結果集網絡/磁盤 IO 成為瓶頸。

場景二:僅查詢 ID 列(結果集 ~22 萬行)

方案耗時說明
MySQL 無索引10s全表掃描
MySQL 有索引0.337s覆蓋索引,無回表
SolrJ /select 僅返回 id7s仍需解析文檔、HTTP 傳輸

優化突破:Solr /export 流式導出

Solr 提供 /export RequestHandler,採用流式排序技術,毫秒級開始輸出,適合大結果集導出。

前置條件

  • 排序字段、導出字段必須使用 docValues 建立索引
  • 支持類型:int, float, long, double, string
  • Schema 配置:
<field name="id" type="long" indexed="true" stored="true" docValues="true" />
<field name="CollectTime" type="tdate" indexed="true" stored="true" docValues="true" />
<field name="DeviceID" type="string" indexed="true" stored="true" docValues="true" />

SolrJ 調用 /export

SolrQuery params = new SolrQuery();
params.set("q", timeQueryString);
params.set("fq", queryString);
params.set("sort", "id asc");      // 必須指定排序
params.set("qt", "/export");       // 關鍵:使用 export handler
params.setFields("id");            // 僅導出 id
params.set("rows", Integer.MAX_VALUE);
QueryResponse response = server.query(params);

SolrJ Bug 繞過:自定義 HTTP 客戶端

SolrJ BinaryResponseParser 硬編碼期望 application/octet-stream,但 Solr 返回 application/json。自行實現 HTTP GET + JSON 解析:

String url = "https://host:8985/solr/core/export?q=...&sort=id+asc&fl=id&wt=json";
long s = System.currentTimeMillis();
SolrHttpJsonClient client = new SolrHttpJsonClient();
SolrQueryResult result = client.getQueryResultByGet(url);
System.out.println("Size: " + result.getResponse().getNumFound()); // 220296
System.out.println("Time: " + (System.currentTimeMillis() - s));   // ~2000ms

場景三:多維聚合統計(按 deviceID 分組計數)

方案耗時說明
MySQL 無索引 GROUP BY33s臨時表 + filesort
MySQL 有索引14s索引掃描聚合
Solr Facet 查詢540ms倒排索引天然適合聚合
SolrQuery query = new SolrQuery();
query.set("q", "*:*");
query.setFacet(true);
query.addFacetField("DeviceID");
QueryResponse response = server.query(query);
FacetField facet = response.getFacetField("DeviceID");
for (Count count : facet.getValues()) {
    System.out.println(count.getName() + ": " + count.getCount());
}

場景四:時間維度下鑽(按天統計某設備數據量)

SolrQuery query = new SolrQuery();
query.set("q", "DeviceID:1013");
query.setFacet(true);
Date start = toSolrDate("2014-12-06 00:00:00");
Date end = toSolrDate("2014-12-16 21:31:55");
query.addDateRangeFacet("CollectTime", start, end, "+1DAY");
QueryResponse response = server.query(query);
// 返回每天文檔數,耗時 662ms

綜合性能對比總結

查詢場景MySQL 無索引MySQL 有索引Solr /selectSolr /exportSolr Facet
範圍查詢全字段30s2s12s--
範圍查詢僅 ID10s0.34s7s2s-
分組統計33s14s--0.54s
時間下鑽----0.66s

架構選型建議

  • MySQL 為主,Solr 為輔:寫入/事務/強一致性走 MySQL;全文檢索、多維聚合、大結果集導出走 Solr
  • 分頁查詢:用 /select(深分頁優化:游標/ID 游標)
  • 全量導出/大結果集:用 /export(需 docValues,字段類型受限)
  • 統計分析/儀表盤:用 Facet/DateRangeFacet,性能碾壓 MySQL
  • 數據同步:DataImportHandler (DIH) 定時全量/增量,或應用雙寫、Canal 解析 Binlog 實時同步

附錄:Solr vs Sphinx/Coreseek 對比(關鍵維度)

維度Sphinx/CoreseekSolr
索引速度10-15 MB/s~10 MB/s
查詢響應<0.1s (2-4GB)150ms (8GB索引)
中文分詞mmseg3 (詞庫靜態)IK/Ansj/mmseg4j (動態擴展詞庫)
實時索引Coreseek 3.x 不支持,4.x 測試版原生支持 NRT (Near Real Time)
增量索引合併主/增量索引分離,合併耗時不可控單索引文件,增量自動合併
多核不支持支持 (SolrCloud)
生態/管理輕量、運維簡單功能豐富、Web UI、SolrCloud 分布式

結論:中文場景、實時性要求高、需分布式擴展選 Solr;極簡部署、純檢索服務可考慮 Sphinx。

copyright © 萬盛學電腦網 all rights reserved