0

私はmysql 5.1で作業しています。

this から this に生成されるクエリを最適化したい:

  • エントリ : ID と名前を持つ「users」テーブル (100 000 エントリ)
  • 出力: 各文字の最初の user_ids とその数

例 :

id | name
1  | Bob
2  | Albert
3  | bernard

出力:

letter | id | count
     A | 2  | 1
     B | 1  | 2

最初の文字 A には 1 人のユーザー (Albert) がいて、文字 B には 2 人のユーザー (bernard と Bob) がいます。アルファベット順の最初の人はバーナードです。

作業クエリがあります。最初のユーザーとカウントとともに、すべての文字 (および「文字なし」) を返します。

SELECT formatted_letter, id, COUNT(1)
FROM (
  SELECT
    CASE WHEN name REGEXP '[A-Za-z].*'
           THEN UPPER(SUBSTR(name, 1, 1))
         ELSE '@'
    END as formatted_letter, id, name
  FROM `users`
    ... (some joins and conditions)
  ORDER BY name
) AS A
GROUP BY formatted_letter

これは完全に機能し、正しい値を返します...しかし、このクエリは非常に時間がかかります(25,000ユーザーの選択で9秒)...

このクエリを最適化する他の方法はありますか?

私が試したこと:

  • 文字ごとに大きな結合を作成します。これは最悪です (36 秒)。
  • 「formatted_letter」列を追加して、CASE/WHEN 部分を削除します。悪くはありません。8 秒かかります。

すべてのインデックスは、ユーザー ID、ユーザー名、および結合と条件のすべてのインデックスに存在します。

4

2 に答える 2

1

ここで考えられるアイデア:-

SELECT FirstLetter, MAX(name), SUM(NameCount)
FROM
(
    SELECT substr(name, 1, 1) AS FirstLetter, MIN(name) AS name, COUNT(*) AS NameCount
    FROM company
    GROUP BY FirstLetter
    UNION
    SELECT 'A' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'B' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'C' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'D' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'E' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'F' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'G' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'H' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'I' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'J' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'K' AS FirstLetter, "" AS name, 0 AS NameCount
    UNION
    SELECT 'L' AS FirstLetter, "" AS name, 0 AS NameCount
) sub1
GROUP BY FirstLetter

(ギャップを埋めるために結合できる文字を入力するのに飽きました)。

これは機能しますが、あなたのサイズのテーブルでのパフォーマンスはわかりません(約14万レコードのランダムテーブル/フィールドで1秒未満かかります)。

編集 - OK 再試行します。

基本的なクエリは次のようになります (空白を埋めることは無視します):-

SELECT CASE WHEN name REGEXP '[A-Za-z].*' THEN UPPER(SUBSTR(name, 1, 1)) ELSE '@' END as formatted_letter, MIN(id) AS id, COUNT(*) AS NameCount
FROM users
GROUP BY formatted_letter

これは、それ自体でかなり効率的なはずです。試してみて、所要時間をお知らせください。

それが速い場合は、組合がゼロカウントレコードを追加するために公称時間を追加する必要があります。

140k レコードのランダム テーブルで試してみると、約 1 秒かかります (名前フィールドはインデックス化されていません)。

結合された選択を追加しても、クエリに顕著な時間が追加されることはありません:-

SELECT formatted_letter, MAX(name), SUM(NameCount)
FROM
(
    SELECT CASE WHEN company REGEXP '[A-Za-z].*' THEN UPPER(SUBSTR(company, 1, 1)) ELSE '@' END as formatted_letter, MIN(id) AS id, COUNT(*) AS NameCount
    FROM users
    GROUP BY formatted_letter
    UNION
    SELECT 'A' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'B' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'C' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'D' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'E' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'F' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'G' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'H' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'I' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'J' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'K' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'L' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'M' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'N' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'O' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'P' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'Q' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'R' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'S' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'T' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'U' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'V' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'W' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'X' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'Y' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT 'Z' AS formatted_letter, "" AS id, 0 AS NameCount
    UNION SELECT '@' AS formatted_letter, "" AS id, 0 AS NameCount
) Sub1
GROUP BY formatted_letter

お使いのマシンでこれに 36 秒程度かかる場合は、おかしなことが起こっています。

于 2013-10-02T13:04:06.987 に答える
0

「文字なし」とはどういう意味ですか。また、公開されている場合は from (他の結合/条件) も最適化できる可能性があります。最低限、名前だけですか...それとも最初の位置に少なくとも名前がありますか?

また、内部の ORDER BY NAME 句を強制終了します。これは、とにかくformatted_letterでグループ化を行っている最終出力に実際の影響がないためです.order byformatted_letterを外側のクエリに追加すると、26のみが返されるためです。 + '@' は記録し、インスタントになります。

于 2013-10-02T12:54:42.870 に答える