4

SQLステートメントを最適化したいと思います。以下は元のステートメントです。

SELECT DISTINCT
    p.productID,
    p.filename,
    p.model,
    p.code,
    p.manufacturerID,
    f2.manufacturerName,
    m.manufacturerName,
    CONCAT('INSERT INTO distribItems(productID, manufacturer, code, distributorText) VALUES (',
            CAST(p.productID AS CHAR),
            ', \'',
            f2.manufacturerName,
            '\', \'',
            f2.code,
            '\', \'',
            f2.denumire,
            '\') ;') INS
FROM
    (SELECT 
        f.manufacturerName, f.categoryName, f.code, f.denumire, f.code_2
    FROM
        furnizorlist f
    LEFT JOIN distribitems d ON 
        (d.manufacturer = f.manufacturerName
        AND (d.code = f.code OR d.manufacturer LIKE 'DELL')
        AND d.distributorText = LEFT(f.denumire, 450))
    WHERE
        productID IS NULL) f2,
    products p,
    manufacturers m
WHERE
    f2.code_2 <> ''
        AND (f2.code_2 = p.code_2 OR f2.code_2 = p.model_2)
        AND p.manufacturerID = m.manufacturerID
        AND m.manufacturerName = f2.manufacturerName
        AND m.manufacturerName != 'Compatibil'
        AND p.code != '1'
ORDER by p.filename ASC;    

私のPCでは約34秒かかります。

スクリーンショット

私のアイデアは、サブクエリを結合として記述し、Where句で条件を設定することでした。

これが私の信じられないほど高速なSQLです。

SELECT DISTINCT
    p.productID,
    p.filename,
    p.model,
    p.code,
    p.manufacturerID,
    f.manufacturerName,
    m.manufacturerName,
    CONCAT('INSERT INTO distribItems(productID, manufacturer, code, distributorText) VALUES (',
            CAST(p.productID AS CHAR),
            ', \'',
            f.manufacturerName,
            '\', \'',
            f.code,
            '\', \'',
            f.denumire,
            '\') ;') INS
FROM
    furnizorlist f,
    distribitems d,
#subquery end
    products p,
    manufacturers m
WHERE
    d.manufacturer = f.manufacturerName
        AND (d.code = f.code OR d.manufacturer LIKE 'DELL')
        AND d.distributorText = LEFT(f.denumire, 450)
        AND d.productID IS NULL
#subquery condions end (f and d tables)
# the next is a subquery result:
        AND f.code_2 <> ''
        AND (f.code_2 = p.code_2 OR f.code_2 = p.model_2)
        AND p.manufacturerID = m.manufacturerID
        AND m.manufacturerName = f.manufacturerName
        AND m.manufacturerName != 'Compatibil'
        AND p.code != '1'
ORDER by p.filename ASC;    

書き込みをexplain improved_sql 行うと、ImpossibleWHERE列が表示されます。試してみましたが、なぜそれが不可能なのかわかりませんでした。フィールドの互換性を確認しました。intとvarcharなどを比較する必要がある場合がないようにするためです。大きなエラーは見つかりませんでした。それが私がここにいる理由です。

WHERE句に論理エラーがありますか?1フィールドになり、後であるように頼むようなもの2ですか?

IDで終わるフィールドはINTで終わり、NAMEで終わるフィールド、コードはvarchar(255)テキストのあるフィールドは450および8192 varchar(1か所のみが使用されます)

翻訳:「denumire」は「説明」を意味します-またはそのようなもの:)

サーバー側で実行されているmysqlのバージョンがわからない(おそらく5)。

正当な理由がある場合は、テーブル構造の変更を提案できます。おそらくコードが調整されます。

編集:

ここから来るのは不可能です:

EXPLAIN 

SELECT 
    f.manufacturerName,
    f.categoryName,
    f.code,
    f.denumire,
    f.code_2
FROM
    furnizorlist f
        INNER JOIN
    distribitems d ON (d.manufacturer = f.manufacturerName
        AND (d.code = f.code
        OR d.manufacturer LIKE 'DELL')
        AND d.distributorText = LEFT(f.denumire, 450))
WHERE
    productID IS NULL

備考:左の結合ではなく、内側の結合。

Edit2:テーブル:furnizorlist 42,751レコードテーブル:distribitems72,290レコード

4

1 に答える 1

1

完全にはわかりませんが、内部テーブルを使用する場合(最初の例です)、多くの人が役立ついくつかのポイントがあります。実際には、引き戻すものを絞り込む必要があります。これは、冗長なwhere句を記述することを意味する場合があります。たとえば、「order_dtが2001年から2002年の間にある場合」は、より小さな内部テーブルとメインクエリで終わる可能性があります。なんで?状況によっては内部テーブルを最適化できないため、サーバーが一時的に取得する行数は数百万行になりますが、必要なのはごくわずかです。

また、あなたの結合の1つに文字列関数「LEFT(f.denumire、450))」があることに気づきました。

結合中はいかなる種類の関数も避ける必要があります。これにより、サーバーはすべてのレコードを(1つずつ)評価する必要があります。最適化できません。これは、結合に常に主キーを使用する必要がある理由と同じ線に沿っていますが、時間がかかります。「like」= AND、NOT、OR、INなどを使用するのが最適です。

于 2012-11-01T06:44:30.443 に答える